简体   繁体   中英

Flatten an array of objects and get unique keys and values by a repeated date with Lodash?

I've been playing around with Lodash and not getting close to a solution that doesn't involve a lot of extra looping and overhead.

data: [
    {
      name: "FirstResult", values: [
        {
          value: { NameCount: 1, OtherCount: 1 },
          date: 2019-05-15T07:00:00+0000
        },
        {
          value: { NameCount: 1 },
          date: 2019-05-16T07:00:00+0000
        }
      ]
    },
    {
      name: "SecondResult",
      values: [
        {
          value: { NameCount: 1 },
          date: 2019-05-15T07:00:00+0000
        },
        {
          value: { BuyCount: 2, SellCount: 1 },
          date: 2019-05-16T07:00:00+0000
        }
      ]
    }
  ]

I'd like to flatten this and have it combined and aggregated by using the date as the key returning some configuration like:

[ 
  { date: 2019-05-15T07:00:00+0000, values: { NameCount: 2, OtherCount: 1 } },
  { date: 2019-05-16T07:00:00+0000, values: { NameCount: 1, BuyCount: 2, SellCount: 1 } }
]

Or even just a flat object array is fine like:

[ 
  { date: 2019-05-15T07:00:00+0000, NameCount: 2, OtherCount: 1 },
  { date: 2019-05-16T07:00:00+0000, NameCount: 1, BuyCount: 2, SellCount: 1 }
]

Does anyone have any ideas on how to do this with either a Lodash or Vanilla solution?

You can use a lodash's chain to flatten, group by the date, and then map and merge each group to a single object:

 const fn = data => _(data) .flatMap('values') // flatten to array of objects .groupBy(o => o.date.toISOString()) // group by the iso representation .map(group => { // map the groups by merging, and converting to require format const { date, value } = _.mergeWith({}, ...group, (objValue, srcValue) => _.isNumber(objValue) ? objValue + srcValue : undefined // combine numeric values ) return { date, ...value, } }) .value() const data = [{"name":"FirstResult","values":[{"value":{"NameCount":1,"OtherCount":1},"date": new Date("2019-05-15T07:00:00.000Z")},{"value":{"NameCount":1},"date": new Date("2019-05-16T07:00:00.000Z")}]},{"name":"SecondResult","values":[{"value":{"NameCount":1},"date":new Date("2019-05-15T07:00:00.000Z")},{"value":{"BuyCount":2,"SellCount":1},"date": new Date("2019-05-16T07:00:00.000Z")}]}] const result = fn(data) console.log(result) 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script> 

Or you can use _.flow() to generate the function ( I'm using lodash/fp here ):

 const { flow, flatMap, groupBy, map, mergeAllWith, cond, isNumber, add } = _ const fn = flow( flatMap('values'), // flatten to array of objects groupBy(o => o.date.toISOString()), // group by the iso representation map(mergeAllWith(cond([[isNumber, add]]))), // combine numeric values map(({ date, value }) => ({ date, ...value })) // format the objects ) const data = [{"name":"FirstResult","values":[{"value":{"NameCount":1,"OtherCount":1},"date": new Date("2019-05-15T07:00:00.000Z")},{"value":{"NameCount":1},"date": new Date("2019-05-16T07:00:00.000Z")}]},{"name":"SecondResult","values":[{"value":{"NameCount":1},"date":new Date("2019-05-15T07:00:00.000Z")},{"value":{"BuyCount":2,"SellCount":1},"date": new Date("2019-05-16T07:00:00.000Z")}]}] const result = fn(data) console.log(result) 
 <script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script> 

Here is pure ES6 solution based on Array.reduce and Array.forEach for the object keys:

 const data = [{"name":"FirstResult","values":[{"value":{"NameCount":1,"OtherCount":1},"date": new Date("2019-05-15T07:00:00.000Z")},{"value":{"NameCount":1},"date": new Date("2019-05-16T07:00:00.000Z")}]},{"name":"SecondResult","values":[{"value":{"NameCount":1},"date":new Date("2019-05-15T07:00:00.000Z")},{"value":{"BuyCount":2,"SellCount":1},"date": new Date("2019-05-16T07:00:00.000Z")}]}] let result = data.reduce((r, { values }) => { values.forEach(({ value, date }) => { let keys = Object.keys(value), d = date.toISOString() r[d] = r[d] || Object.assign({}, ...keys.map(x => ({ date: d, [x]: 0 }))) keys.forEach(k => r[d][k] = (r[d][k] || 0) + value[k]) }) return r }, {}) console.log(Object.values(result)) 

The main idea is to get the keys of the value object white iterating and compose an object with them while grouping by the date. Then last forEach just sums each result object value.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM