abyrne85
abyrne85

Reputation: 1450

Merge array of objects based on key value

How would I turn an array of objects like this

const scores = [
{
   year: 2020,
   dave: 20
},
{
   year: 2020,
   steve: 17
},
{
   year: 2019,
   bill: 18
}
];

into this

const scores = [
{
   year: 2020,
   dave: 20,
   steve: 17
},
{
   year: 2019,
   bill: 18
}
];

Upvotes: 0

Views: 57

Answers (3)

Ori Drori
Ori Drori

Reputation: 191976

You can create a function with _.flow() that uses _.groupBy() to collect items with the same year to arrays, and then maps and merges the arrays:

const { flow, groupBy, map, merge } = _;;

const fn = flow(
  arr => groupBy(arr, 'year'),
  groups => map(groups, g => merge({}, ...g))
);

const scores = [{"year":2020,"dave":20},{"year":2020,"steve":17},{"year":2019,"bill":18}];

const result = fn(scores);

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>

Using lodash/fp makes this solution even more concise:

const fn = flow(
  groupBy('year'),
  map(mergeAll)
);

const scores = [{"year":2020,"dave":20},{"year":2020,"steve":17},{"year":2019,"bill":18}];

const result = fn(scores);

console.log(result);
<script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>

However, since _.mergeBy() creates an object, grouping by a number, will change the order of the groups (2020 after 2019). You can reduce the array to a Map to preserve the order, and then convert it to an array by spreading the Map's value iterator:

const scores = [{"year":2020,"dave":20},{"year":2020,"steve":17},{"year":2019,"bill":18}];

const result = [...scores.reduce((r, o) => 
  r.set(o.year, { ...r.get(o.year), ...o })
, new Map()).values()];

console.log(result);

Upvotes: 0

Bhasyakarulu Kottakota
Bhasyakarulu Kottakota

Reputation: 833

Are you looking for this?

<!DOCTYPE html>
<html>

<head>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>

<body>
  <script>
    $(function () {
        const scores = [
            {
                year: 2020,
                dave: 20
            },
            {
                year: 2020,
                steve: 17
            },
            {
                year: 2019,
                bill: 18
            }
        ];

        var groupBy = function (xs, key) {
            return xs.reduce(function (rv, x) {
                (rv[x[key]] = rv[x[key]] || []).push(x);
                return rv;
            }, {});
        };

        console.log(groupBy(scores, 'year'));
    })
</script>
</body>
</html>

Upvotes: 1

Ashish Ranjan
Ashish Ranjan

Reputation: 12960

I used an Array.reduce() and to have an Object with keys as year and kept assigning the Objects, later took out the values.

const scores = [
  {
     year: 2020,
     dave: 20
  },
  {
     year: 2020,
     steve: 17
  },
  {
     year: 2019,
     bill: 18
  }
];

const mergedOb = scores.reduce((acc, ob) => {
  if (acc[ob.year]) {
    Object.assign(acc[ob.year], ob);
  } else {
    acc[ob.year] = ob
  }
  return acc;
}, {});

const mergeArr = Object.values(mergedOb)
console.log(mergeArr)

Upvotes: 1

Related Questions