skip to Main Content

I have an array of objects that have 2 fields key and type, the type field is practice or theory

Result:

  1. group the array by key

  2. transform the array: in the new array the object with type practice should come in the even index and object with type theory should be in the odd index. (check the input and the output if my explanation wasn’t clear)

here’s my code but it doesn’t work as expected in the transform the array

function transformArray(arr) {
  const grouped = arr.reduce((result, item) => {
    const key = item.key;
    if (!result[key]) {
      result[key] = { key, values: [] };
    }
    result[key].values.push(item);
    return result;
  }, {});

  for (const group in grouped) {
    const values = grouped[group].values;
    const newValues = [];
    for (let i = 0; i < values.length; i++) {
      const item = values[i];
      if (item.type === 'practice' && i % 2 === 0) {
        newValues.push(item);
      } else if (item.type === 'theory' && i % 2 === 1) {
        newValues.push(item);
      }
    }
    grouped[group].values = newValues;
  }

  return Object.values(grouped);
}

example input:

const input = [
{ key: 'A', type: 'practice' },
{ key: 'A', type: 'practice' },
{ key: 'A', type: 'theory' },
{ key: 'A', type: 'theory' },

{ key: 'B', type: 'practice' },
{ key: 'B', type: 'theory' },
{ key: 'B', type: 'practice' },

{ key: 'C', type: 'practice' },
{ key: 'C', type: 'theory' },
{ key: 'C', type: 'practice' },
]

OUTPUT should be like the following

[
  {
    key: 'A',
    values: [
      { key: 'A', type: 'practice'},  // index = even ==> practice
      { key: 'A', type: 'theory' },    // index = odd ==> theory
      { key: 'A', type: 'practice'}, // index = even ==> practice
      { key: 'A', type: 'theory'}, // index = odd ==> theory
    ],
  },
  {
    key: 'B',
    values: [
      { key: 'B', type: 'practice' },
      { key: 'B', type: 'theory',},
      { key: 'B', type: 'practice' },
    ],
  },
  {
    key: 'C',
    values: [
      { key: 'C', type: 'practice' },
      { key: 'C', type: 'theory', },
      { key: 'C', type: 'practice'},
    ],
  },
]

my code is kinda broken, and I wonder how to achieve this output?

2

Answers


  1. All this can be done in one use of the reduce method:

    const input = [
    { key: 'A', type: 'practice' },
    { key: 'A', type: 'practice' },
    { key: 'A', type: 'theory' },
    { key: 'A', type: 'theory' },
    
    { key: 'B', type: 'practice' },
    { key: 'B', type: 'theory' },
    { key: 'B', type: 'practice' },
    
    { key: 'C', type: 'practice' },
    { key: 'C', type: 'theory' },
    { key: 'C', type: 'practice' },
    ]
    
    const output = input.reduce((prev, current) => {
      if (!prev[current.key]?.key){
        prev[current.key] = {
          key: '',
          values: []
        };
      }
      const object =  prev[current.key];
      object.key = current.key;
      object.values.push({
        key: current.key,
        type: ''
      });
      const index = object.values.length - 1;
      const keys = ['practice', 'theory'];
      if (keys.includes(current.type)) {
        object.values[index].type =  index % 2 === 0 ?  keys[0] : keys[1];
      } else{
        object.values[index].type = current.type;
      }
      
      return prev;
    }, {})
    
    console.log(output);
    Login or Signup to reply.
  2. I suggest you not to squash everything into one function but instead implement a few small utility functions (you can use a library like lodash for that).

    So you have 2 separate util steps

    1. Group array by key and then by type
    2. Interleave two arrays for practice and theory.
    function transform(arr) {
      const result = []
    
      for (const [key, value] of groupBy('key', arr).entries()) {
        const byType = groupBy('type', value)
    
        result.push({
          key,
          values: interleave(
            byType.get('practice') ?? [], byType.get('theory') ?? [],
          ),
        })
      }
    
      return result
    
    }
    
    
    const input = [{"key":"A","type":"practice"},{"key":"A","type":"practice"},{"key":"A","type":"theory"},{"key":"A","type":"theory"},{"key":"B","type":"practice"},{"key":"B","type":"theory"},{"key":"B","type":"practice"},{"key":"C","type":"practice"},{"key":"C","type":"theory"},{"key":"C","type":"practice"}]
    
    console.log(transform(input))
    
    // Utils
    function groupBy(by, arr) {
      const out = new Map
    
      for (const item of arr) {
        const key = item[by]
    
        if (out.has(key)) {
          out.get(key).push(item)
        } else {
          out.set(key, [item])
        }
      }
    
      return out
    }
    
    function interleave(a, b) {
      const out = []
      const len = Math.max(a.length, b.length)
    
      for (let i = 0; i < len; i++) {
        if (i < a.length) out.push(a[i])
        if (i < b.length) out.push(b[i])
      }
    
      return out
    }
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search