yerpasaur
yerpasaur

Reputation: 21

Javascript Combine Items in An Array Object

I discovered _.reduce however it only keeps 1 of set of information. What option should be used to combine like information?

[
  {
    fruit: 'apple',
    'color': 'red'
  },
  {
    fruit: 'apple',
    'color': 'green'
  },
  {
    fruit: 'pear',
    'color': 'yellow'
  },
  {
    fruit: 'pear',
    'color': 'green'
  }
]

My desired outcome would be:

var items = [
  {
    fruit: 'apple',
    'color': 'red', 'green'
  },
  {
    fruit: 'pear',
    'color': 'green', 'yellow'
  }
]

The current code I have using NodeJS is:

 let result = Object.values(json.reduce((c, {fruit,...r}) => {
   c[fruit] = c[fruit] || {fruit};
   c[fruit] = Object.assign(c[fruit], r);
   return c;
 }, {}));

Upvotes: 2

Views: 93

Answers (3)

Siva Kondapi Venkata
Siva Kondapi Venkata

Reputation: 11001

Use simple forEach and build the object of unique keys and get the values using Object.values.

const data = [
  {
    fruit: "apple",
    color: "red"
  },
  {
    fruit: "apple",
    color: "green"
  },
  {
    fruit: "pear",
    color: "yellow"
  },
  {
    fruit: "pear",
    color: "green"
  }
];

const res = {};

data.forEach(
  item =>
    (res[item.fruit] =
      item.fruit in res
        ? { ...res[item.fruit], color: [...res[item.fruit].color, item.color] }
        : { fruit: item.fruit, color: [item.color] })
);

const output = Object.values(res);

console.log(output);

Upvotes: 0

see sharper
see sharper

Reputation: 12035

This is an approach that runs in time O(n) instead of O(n^2):

const arr = [
  {
    fruit: 'apple',
    'color': 'red',
  },
  {
    fruit: 'apple',
    'color': 'green',
  },
  {
    fruit: 'pear',
    'color': 'yellow',
  },
  {
    fruit: 'pear',
    'color': 'green',
  },
];
const map = arr.reduce((acc, o) => {
  if (acc[o.fruit]) {
    acc[o.fruit].push(o.color);
  } else {
    acc[o.fruit] = [o.color];
  }
  return acc;
}, {});
const result = Object.keys(map).map(k => ({ fruit: k, colors: map[k] }));
console.log(result);
return result;

Note that, as noted in Nick's answer, the difference won't make a difference for a small array, but if the array is large, or the transformation is itself wrapped in a loop, it may matter.

Upvotes: 2

Nick
Nick

Reputation: 16576

You can use the Array reduce method for this. Assuming your array isn't super long, using the find method on each iteration shouldn't be too expensive. If it's a super long array, you might instead opt for an intermediate object that has hash table efficiency. Probably not necessary, though.

const arr = [
  {
    fruit: 'apple',
    'color': 'red'
  },
  {
    fruit: 'apple',
    'color': 'green'
  },
  {
    fruit: 'pear',
    'color': 'yellow'
  },
  {
    fruit: 'pear',
    'color': 'green'
  }
];

const combined = arr.reduce((acc, el) => {
  const fruit = acc.find(item => item.fruit === el.fruit);
  if (fruit) {
    fruit.colors.push(el.color)
  } else {
    acc.push({ fruit: el.fruit, colors: [el.color] });
  }
  return acc;
}, []);

console.log(combined);

Upvotes: 1

Related Questions