0

I am trying to merge the array itself and convert it into a more meaningful array

array = [
{item: 'pen', madeIn: 'US', color: 'blue'},
{item: 'pen', madeIn: 'US', color: 'white'},
{item: 'pen', madeIn: 'China', color: 'red'},
{item: 'pen', madeIn: 'China', color: 'white'}
]

the output array that i want to produce :

outputArray = [
{item: 'pen', madeIn: 'US', color: ['blue', 'white']},
{item: 'pen', madeIn: 'China', color: ['red', 'white']}
];

I have been trying but no luck, the only solution that i can think of at the moment is that using a temporary variable to store the item and madeIn value. and the run another loop to compare item and madeIn and then add color to an array. There is several loop to solve this problem.

I mean it does the work, but definitely not an optimal solution. any other ideal will be welcome. Thank you.

3 Answers 3

4

Reduce the array to an object using the item and madeIn properties to create a key. For each object, check if the key already exists, and if not create a new object for the key with property color as an empty array. Push the color of each object to the array. Use Object.values() to convert the object to an array.

const array = [{"item":"pen","madeIn":"US","color":"blue"},{"item":"pen","madeIn":"US","color":"white"},{"item":"pen","madeIn":"China","color":"red"},{"item":"pen","madeIn":"China","color":"white"}]

const result = Object.values(
  array.reduce((r, o) => {
    const key = `${o.item}-${o.madeIn}`
    
    if(!r[key]) r[key] = { ...o, color: [] }
    
    r[key].color.push(o.color)
    
    return r;
  }, {})
)

console.log(result)

Sign up to request clarification or add additional context in comments.

7 Comments

Can you please explain how the hyphenated key works? I don't get how the key works.
I was just playing on the console and figured you started with an object for your accumulator and then got the keys for the final result. This solution is not valid as the keys of an object are not guaranteed to be in any particular order, so if order is important this is not a valid solution.
@AdrianBrand - ES6 actually defined traversal order for object keys. The basic idea is that integer keys are traversed by their numeric order, while strings keys are traversed in the insertion order. So my solution does keep the original order. Read more about it in this article.
The hyphenated key works because a key like pen-blue is unique enough in the current case to work. If not, you can use another separator, or combination of the original keys.
Good to know that string keys are traversed by insertion order. ES5 this was not guaranteed to be the case so there were a few instances where I didn't use object keys but would have if I knew ES6 guaranteed preserving insertion order. Thanks, I learned something useful today.
|
1

Use reduce:

const array = [{ item: 'pen', madeIn: 'US', color: 'blue' }, { item: 'pen', madeIn: 'US', color: 'white' }, { item: 'pen', madeIn: 'China', color: 'red' }, { item: 'pen', madeIn: 'China', color: 'white' }];

const output = Object.values(array.reduce((acc, { item, madeIn, color}) => {
  acc[`${item}-${madeIn}`] = acc[`${item}-${madeIn}`] || { item, madeIn, color: [] };
  acc[`${item}-${madeIn}`].color.push(color);
  return acc;
}));

console.log(output);

Comments

1

Here is a solution that uses Array.prototype.reduce() and object destructuring:

const initialArray = [
  {item: 'pen', madeIn: 'US', color: 'blue'},
  {item: 'pen', madeIn: 'US', color: 'white'},
  {item: 'pen', madeIn: 'China', color: 'red'},
  {item: 'pen', madeIn: 'China', color: 'white'}
];

const finalArray = initialArray.reduce((accumulator, currentValue) => {
  const item = accumulator.find(x => x.item === currentValue.item && x.madeIn === currentValue.madeIn);
  if(item) {
    item.color.push(currentValue.color);
  }
  else {
    accumulator.push({...currentValue, color: [currentValue.color]});
  }
  return accumulator; 
}, []);

console.log(finalArray);

Unlike other answers, this is not based on a "not so unique" key and will work for any data.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.