Home > Back-end >  Convert an array of objects to an array of arrays grouped preserving the order - Javascript
Convert an array of objects to an array of arrays grouped preserving the order - Javascript

Time:03-10

I have an array of objects and I need to convert it into an array of arrays grouped together based on position, but maintaining the order of the items.

This is what I did:

const data = [{
  position: 'left',
  message: 'a'
}, {
  position: 'left',
  message: 'b'
}, {
  position: 'left',
  message: 'c'
}, {
  position: 'right',
  message: 'd'
}, {
  position: 'right',
  message: 'e'
}, {
  position: 'left',
  message: 'f'
}, {
  position: 'left',
  message: 'g'
}]

console.log(data.reduce((a, c) => {
  let b = [];
  let d = [];
  if (c.position === 'left') {
    b.push(c.message)
  }
  if (c.position === 'right') {
    d.push(c.message)
  }
  a.push(b)
  return a
}, []))

Expected output:

[['a', 'b', 'c'], ['d', 'e'], ['f', 'g']]

The same position elements are grouped together in an array and if the next position is different, it is grouped together in a different array and goes on. For example, 'a' 'b' 'c' are position left and they are grouped inside an array, 'd' 'e' are positioned right, they are grouped together as the second array and 'f' 'g' are left positioned, they are grouped as 3rd array.

Thanks.

CodePudding user response:

Hard-coding the creation of two arrays won't be enough, especially not inside the .reduce callback. If you need to use .reduce here (which I wouldn't recommend because it looks a bit convoluted), use the iteration index to check the last index to see which position was used there. If it's different from the current index's position, push a new array to the accumulator. Finally, unconditionally push the current message to the last array in the accumulator.

const data = [{
  position: 'left',
  message: 'a'
}, {
  position: 'left',
  message: 'b'
}, {
  position: 'left',
  message: 'c'
}, {
  position: 'right',
  message: 'd'
}, {
  position: 'right',
  message: 'e'
}, {
  position: 'left',
  message: 'f'
}, {
  position: 'left',
  message: 'g'
}]

console.log(data.reduce((a, { position, message }, i, arr) => {
  const lastPosition = arr[i - 1]?.position;
  if (lastPosition !== position) a.push([]);
  a[a.length - 1].push(message);
  return a
}, []))

Without .reduce, and probably more readably:

const data = [{
  position: 'left',
  message: 'a'
}, {
  position: 'left',
  message: 'b'
}, {
  position: 'left',
  message: 'c'
}, {
  position: 'right',
  message: 'd'
}, {
  position: 'right',
  message: 'e'
}, {
  position: 'left',
  message: 'f'
}, {
  position: 'left',
  message: 'g'
}];

let lastPosition;
const result = [];
for (const { position, message } of data) {
  if (position !== lastPosition) result.push([]);
  result[result.length - 1].push(message);
  lastPosition = position;
}
console.log(result);

CodePudding user response:

You could group by looking to the previous object.

const
    data = [{ position: 'left', message: 'a' }, { position: 'left', message: 'b' }, { position: 'left', message: 'c' }, { position: 'right', message: 'd' }, { position: 'right', message: 'e' }, { position: 'left', message: 'f' }, { position: 'left', message: 'g' }],
    result = data.reduce((r, o, i, a) => {
        if (o.position !== a[i - 1]?.position) r.push([]);
        r[r.length - 1].push(o);
        return r;
    }, []);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

  • Related