7

I guess I have a dead simple problem but still didn't find a solution. I have an array which looks like this:

var originalArray = [{
  id: 1,
  elements: [1, 2]
},
{
  id: 1,
  elements: [3, 4]
},
{
  id: 5,
  elements: ['a', 'b']
},
{
  id: 5,
  elements: ['c', 'd']
}, {
  id: 27,
  elements: []
}]

I'd like to modify it to look like this (merge by id and join elements):

newArray = [{
  id: 1,
  elements: [1, 2, 3, 4]
}, {
  id: 5,
  elements: ['a', 'b', 'c', 'd']
}, {
  id: 27,
  elements: []
}]

I already had multiple tries but still didn't find an elegant way of doing it.

2
  • 6
    Hi! Please take the tour (you get a badge!) and read through the help center, in particular How do I ask a good question? Your best bet here is to do your research, search for related topics on SO, and give it a go. If you get stuck and can't get unstuck after doing more research and searching, post a minimal reproducible example of your attempt and say specifically where you're stuck. People will be glad to help. Commented Nov 4, 2019 at 11:24
  • So by looking at the solutions below, it was not dead simple ;) Commented Nov 4, 2019 at 14:20

7 Answers 7

9

You can create an object keyed by ID and push elements with the same ID to them, then convert back to an array. This is more efficient than looping through on every iteration for larger arrays:

var originalArray = [{
  id: 1,
  elements: [1, 2]
},
{
  id: 1,
  elements: [3, 4]
},
{
  id: 5,
  elements: ['a', 'b']
},
{
  id: 5,
  elements: ['c', 'd']
}, {
  id: 27,
  elements: []
}];

const arrayHashmap = originalArray.reduce((obj, item) => {
  obj[item.id] ? obj[item.id].elements.push(...item.elements) : (obj[item.id] = { ...item });
  return obj;
}, {});

const mergedArray = Object.values(arrayHashmap);

console.log(mergedArray);

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

2 Comments

why use ... in javaScript
The ... in push is necessary if passing multiple items, or you could use concat(item.elements) but would need to assign elements to it as it returns a new array. The ...item is just common practice to "break" away from the original array so that (shallow) modifications to the object will not change the original array - generally this style of immutable coding causes less unexpected side effects and also makes object equality comparison much more efficient and easy e.g. reactjs.org/docs/react-api.html#reactpurecomponent is made possible by it
3

Try this code :

var originalArray = [{
      id: 1,
      elements: [1, 2]
    },
    {
      id: 1,
      elements: [3, 4]
    },
    {
      id: 5,
      elements: ['a', 'b']
    },
    {
      id: 5,
      elements: ['c', 'd']
    }, {
      id: 27,
      elements: []
    }]
    var newArray = [];
    originalArray.forEach(item => {
       var newItem = {id: item.id, elements: []};
       originalArray.forEach(innerItem => {
          if(innerItem.id == item.id){
              newItem.elements = newItem.elements.concat(innerItem.elements);
          }
       });
      newArray.push(newItem);
    });
    console.log(newArray);

Output :

[{
  id: 1,
  elements: [1, 2, 3, 4]
}, {
  id: 5,
  elements: ['a', 'b', 'c', 'd']
}, {
  id: 27,
  elements: []
}]

Comments

2

You can use Array.prototype.reduce() to create an object with the ids as properties and the Object.values() to get the result:

const originalArray = [{id: 1, elements: [1, 2]}, {id: 1, elements: [3, 4]}, {id: 5, elements: ['a', 'b']}, {id: 5, elements: ['c', 'd']}, {id: 27, elements: []}]
const objIds = originalArray.reduce((a, { id, elements }) => {
  a[id] = a[id] || {id, elements: []}
  return {...a, ...{[id]: {id, elements: a[id].elements.concat(elements)}}}
}, {})
const result = Object.values(objIds)

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

Comments

2

You could do this using reduce method and Map to store unique values for each id and then create an array using spread syntax ....

var data = [{"id":1,"elements":[1,2]},{"id":1,"elements":[3,4]},{"id":5,"elements":["a","b"]},{"id":5,"elements":["c","d"]},{"id":27,"elements":[]}]

const result = data.reduce((r, {id, elements}) => {
  if(r.get(id)) r.get(id).elements.push(...elements);
  else r.set(id, {id, elements});
  return r;
}, new Map).values();

console.log([...result])

Comments

1

You can do this with a reduce function:

[{
  id: 1,
  elements: [1, 2]
},
{
  id: 1,
  elements: [3, 4]
},
{
  id: 5,
  elements: ['a', 'b']
},
{
  id: 5,
  elements: ['c', 'd']
}, {
  id: 27,
  elements: []
}].reduce((prev, cur) => {
    const index = prev.findIndex(v => v.id === cur.id);
    if (index === -1) {
       prev.push(cur);
    } else {
        prev[index].elements.push(...cur.elements);
    }
    return prev;
}, [])

Comments

1

This will work and is also decently easy to understand. Firstly we check if the id is already in the newArray or not and we keep memory of this through a boolean outside the loop that we can verify later on. After this, if the id "space" is empty, we will fill it up, if it isn't then there is already an id there. Therefore, we need to update their elements. We can do this by firstly, grabbing the object in the new array that corresponds with the duplicate object in the initial array which has the same id. After this, we simply push each element from the duplicate to the new one.


var originalArray = [{
  id: 1,
  elements: [1, 2]
},
{
  id: 1,
  elements: [3, 4]
},
{
  id: 5,
  elements: ['a', 'b']
},
{
  id: 5,
  elements: ['c', 'd']
}, {
  id: 27,
  elements: []
}]

var newArray = [];
for (obj of originalArray) {

    var empty = true;
    for (newobj of newArray) {
       if (obj.id == newobj.id) { empty = false; }
    }
    if (empty) {
        newArray.push({id: obj.id, elements: obj.elements});
    } else {
        for (newobj of newArray) {
           if (newobj.id == obj.id) {
               for (o of obj.elements) {
                 newobj.elements.push(o);
                }
           }
        }
    }
}
console.log(newArray);

Comments

1

You can use nested for loops to do that.

var originalArray = [{
  id: 1,
  elements: [1, 2]
},
{
  id: 1,
  elements: [3, 4]
},
{
  id: 5,
  elements: ['a', 'b']
},
{
  id: 5,
  elements: ['c', 'd']
}, {
  id: 27,
  elements: []
}]


for(let i=0;i<originalArray.length;i++){
  let key = originalArray[i].id;
  for(let j=i+1;j<originalArray.length;j++){
    if(originalArray[j].id == key){
      originalArray[i].elements  = [...originalArray[i].elements,...originalArray[j].elements];
      delete originalArray.splice(j,1);
    }

  }
}

console.log(originalArray);

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.