1

I am trying to merge values in 2 objects from the same array. The objects in this case are similar and the values I want to merge are arrays(Set)

var array = [
  {
  name: "foo1",
  value: ["val1","val2"]
}, 
{
  name: "foo1",
  value: ["val2", "val3"]
}, 
{
  name: "foo2",
  value: ["val4"]
},
 {
  name: "foo2",
  value: ["val4","val5"]
},
];

Expected Output

[
{
  name: "foo1",
  value: ["val1","val2", "val3"]
},{
  name: "foo2",
  value: ["val4","val4", "val5"]
}
]

My Code

var output = [];

array.forEach(function(item) {
  var existing = output.filter(function(v, i) {
    return v.name == item.name;
  });
  if (existing.length) {
    var existingIndex = output.indexOf(existing[0]);
    let newValue = new Set(output[existingIndex].value).add(item.value)
    output[existingIndex].value = Array.from(newValue);
  } else {
    output.push(item);
  }
});

Output Gotten

[ {
  name: "foo1",
  value: ["val1", "val2", ["val2", "val3"]]
}, {
  name: "foo2",
  value: ["val4", ["val4", "val5"]]
}]

How can I get the expected output (ES6 would also be preferred)

1
  • The expected output should be value: ["val4", "val5"] instead of value: ["val4","val4", "val5"], is that right? Commented Jan 7, 2021 at 10:31

8 Answers 8

2

Try this

const array = [
  {
    "name": "foo1",
    "value": [
      "val1",
      "val2",
      "val3"
    ]
  },
  {
    "name": "foo1",
    "value": [
      "val2",
      "val3"
    ]
  },
  {
    "name": "foo2",
    "value": [
      "val4",
      "val5"
    ]
  },
  {
    "name": "foo2",
    "value": [
      "val4",
      "val5"
    ]
  }
]

const result = []

for (const item of array) {
  const existingItem = result.find(i => i.name === item.name)
  if (existingItem) {
    existingItem.value = [...new Set([...existingItem.value, ...item.value])]
  } else {
    result.push(item)
  }
}

console.log(result)

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

Comments

1

Is this code solve your problem?

var array = [
    {
    name: "foo1",
    value: ["val1","val2"]
  }, 
  {
    name: "foo1",
    value: ["val2", "val3"]
  }, 
  {
    name: "foo2",
    value: ["val4"]
  },
   {
    name: "foo2",
    value: ["val4","val5"]
  },
  ];

  var output = [];

array.forEach(function(item) {
  var existing = output.filter(function(v, i) {
    return v.name == item.name;
  });
  if (existing.length) {
    var existingIndex = output.indexOf(existing[0]);
    let newValue = new Set(output[existingIndex].value.concat(item.value))
    output[existingIndex].value = Array.from(newValue);
  } else {
    output.push(item);
  }
});

Comments

1

try

var arr = [
  {
  name: "foo1",
  value: ["val1","val2"]
}, 
{
  name: "foo1",
  value: ["val2", "val3"]
}, 
{
  name: "foo2",
  value: ["val4"]
},
 {
  name: "foo2",
  value: ["val4","val5"]
},
];
var arr2={}
arr.map((elem,ind)=>{
    if(!arr2[elem.name]){
        arr2[elem.name]=[]
    }
    arr2[elem.name]=[...arr2[elem.name],...elem.value]
})
arr=Object.keys(arr2);
arr.map((elem,ind)=>{
    arr[ind]={name:elem,value:arr2[elem]};
})

Comments

1

You can do the following using reduce,

var array = [
  {
  name: "foo1",
  value: ["val1","val2"]
}, 
{
  name: "foo1",
  value: ["val2", "val3"]
}, 
{
  name: "foo2",
  value: ["val4"]
},
 {
  name: "foo2",
  value: ["val4","val5"]
},
];

res = array.reduce((prev, curr) => {
  let index = prev.findIndex(item => item.name === curr.name);
 
  if(index > -1) {
    s = new Set([...prev[index].value, ...curr.value]);
    prev[index].value = Array.from(s);
  } else {
    prev.push(curr);
  }
  return prev;
},[]);

console.log(res);

Comments

1

You could use reduce method with a Map as accumulator value and then use spread syntax ... on Map values to get an array of values.

var array = [{"name":"foo1","value":["val1","val2","val2","val3"]},{"name":"foo1","value":["val2","val3"]},{"name":"foo2","value":["val4","val4","val5"]},{"name":"foo2","value":["val4","val5"]}]

const map = array.reduce((r, { name, value }) => {
  if (!r.has(name)) r.set(name, { name, value })
  else r.get(name).value.push(...value)
  r.get(name).value = [...new Set(r.get(name).value)]
  return r;
}, new Map)

const result = [...map.values()]

console.log(result)

Comments

1

One approach is to create an unique list of keys and iterate over it. Create an array for each key and merge the values. The vanilla js way is:

Array.from(new Set(array.map(el => el.name)))
    .map(name => ({
        name,
        value: Array.from(new Set(array.filter(el => el.name === name).flatMap(el => el.value)))
    }))

Example:

const array = [
  {
  name: "foo1",
  value: ["val1","val2"]
}, 
{
  name: "foo1",
  value: ["val2", "val3"]
}, 
{
  name: "foo2",
  value: ["val4"]
},
 {
  name: "foo2",
  value: ["val4","val5"]
},
];

console.log(Array.from(new Set(array.map(el => el.name)))
.map(name => ({
    name,
    value: Array.from(new Set(array.filter(el => el.name === name).flatMap(el => el.value)))
})));

Using lodash you can reduce it to

_.uniq(array.map(el => el.name))
    .map(name => ({
        name,
        value: _.uniq(array.filter(el => el.name === name).flatMap(el => el.value))
    }))

Example:

const array = [
  {
  name: "foo1",
  value: ["val1","val2"]
}, 
{
  name: "foo1",
  value: ["val2", "val3"]
}, 
{
  name: "foo2",
  value: ["val4"]
},
 {
  name: "foo2",
  value: ["val4","val5"]
},
];

console.log(_.uniq(array.map(el => el.name))
    .map(name => ({
        name,
        value: _.uniq(array.filter(el => el.name === name).flatMap(el => el.value))
    })));
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>

Comments

1

Find unique values of keys. Match this keys within array and return unique objects. Push this objects in an empty array. Then match other objects value with the new arrays objects value and push the unmatched values to this new array.

var arr = [
                {
                name: "foo1",
                value: ["val1","val2"]
              }, 
              {
                name: "foo1",
                value: ["val2", "val3"]
              }, 
              {
                name: "foo2",
                value: ["val4"]
              },
               {
                name: "foo2",
                value: ["val4","val5"]
              },
];

let key = [];
arr.map((val)=>key.push(val.name));
let uniquekeys = [...new Set(key)]; //unique values of keys

let newarr = [];
uniquekeys.map((uniquekey,ind)=>{

        let reduceunique = arr.filter((vals)=>uniquekey == vals.name);   // return matching objects as array     
        newarr.push(reduceunique[0]); // Push unique objects in an empty array
        
        for(let i = 1; i<uniquekeys.length;i++){ 
                reduceunique[i].value.map((val)=>{
                        let existvalue = newarr[ind].value.indexOf(val); // Match every value with the unique objects values
                                if(existvalue<0){
                                        newarr[ind].value.push(val); // push the unmatched value in the array
                                }
                });
        };
});
console.log(newarr);

Comments

0

try to use Array.reduce and Array.filter to get the result like the following

var array = [
  {
  name: "foo1",
  value: ["val1","val2"]
}, 
{
  name: "foo1",
  value: ["val2", "val3"]
}, 
{
  name: "foo2",
  value: ["val4"]
},
 {
  name: "foo2",
  value: ["val4","val5"]
},
];

res = array.reduce((prev, curr) => {
  let index = prev.findIndex(item => item.name === curr.name);
 
  if(index > -1) {
    
    prev[index].value = [...prev[index].value, ...curr.value];
    prev[index].value = prev[index].value.filter((v,i) => prev[index].value.indexOf(v) === i)
  } else {
    prev.push(curr);
  }
  return prev;
},[]);

console.log(res);

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.