emka26
emka26

Reputation: 443

Merge object with same value

I have array like bellow:

var array = [{name: 'abc', age: 17}, {name: 'cde', age: 20}, {name: 'abc', age: 89}]

I would like to have output like:

array = [{name: 'abc', age: [17, 89]}, {name: 'cde', age: 20}]

How can achieve it? I tried many solutions like eg:

var result = _(array)
      .groupBy('name')
      .map(_.spread(_.assign))
      .value();

but it's not what I want because I would like to have array of values age.

Upvotes: 1

Views: 95

Answers (5)

Ghoul Ahmed
Ghoul Ahmed

Reputation: 4806

try this

const data  = [{name: 'abc', age: 17}, {name: 'cde', age: 20}, {name: 'abc', age: 89}]
         
const groupBy = (arr) => data.reduce((acc, ele)=>( (acc[ele.name] = acc[ele.name] || []).push(ele), acc),{})
const displayAge= v => v.length>1?v.map(e=>e.age):v[0].age

console.log(Object.entries(groupBy(data)).map(([name, v])=>({name, age: displayAge(v)})))

Upvotes: 1

Walk
Walk

Reputation: 757

Would be easier if you always kept age as an array instead of being Number when only one value is present.

const array = [{name: 'abc', age: 17}, {name: 'cde', age: 20}, {name: 'abc', age: 89}]
const newArray = array.reduce((arr, i) => {
    const inArray = arr.findIndex(a => a.name === i.name);
    if (inArray < 0) arr.push(i);
    else {
        if (Array.isArray(arr[inArray].age)) {
            arr[inArray].age.push(i.age);
        } else {
            arr[inArray].age = [arr[inArray].age, i.age];
        }
    }
    return arr;
}, [])

console.log(newArray);

Upvotes: 0

cs95
cs95

Reputation: 402253

You can create a map (which is constant time lookup), then convert it to an array. Not the prettiest solution, but definitely performant in terms of complexity (linear).

const array = [{name: 'abc', age: 17}, {name: 'cde', age: 20}, {name: 'abc', age: 89}]

const m = new Map();
array.map(x => {
    if (!m.has(x.name)) {
        m.set(x.name, []);
    }
    m.get(x.name).push(x.age);
});

console.log(Array.from(m).map(
    (x) => Object.assign({'name': x[0], 'age': x[1]})));

Upvotes: 1

faebzz
faebzz

Reputation: 151

What about:

var result = array.forEach(a => {
    let similar = array.filter(b => b.name == a.name).map(c => c.age);
    a.age = similar.length > 1 ? similar : a.age;
}).filter((d,e) => array.indexOf(d) == e);

Upvotes: 0

Mortimer
Mortimer

Reputation: 392

Well I don't understand why aren't you using loops or anything.. You didn't specify format so here have my code in vanila js:

var array = [{name: 'abc', age: 17}, {name: 'cde', age: 20}, {name: 'abc', age: 89}]

for (var i = 0; i < array.length; i++) {
  for (var j = i + 1; j < array.length; j++) {
    if (array[i].name == array[j].name) {
      if (Array.isArray(array[i].age)) {
        array[i].age.push(array[j].age)
      } else {
        var arAge = [array[i].age, array[j].age];
        array[i].age = arAge;
      }
      array.splice(j,1);
      j--;
    }
  }
}

Upvotes: 0

Related Questions