首页 > 解决方案 > 合并缺少键的对象

问题描述

我有两个这样的对象:

const object1 = {first: [{timestamp: "2018-12-09T16:00:00.000", count: 3}], second: [{timestamp: "2018-12-09T17:00:00.000", count: 2}], third: [{timestamp: "2018-12-09T18:00:00.000", count: 2}]}
const object2 = {first: [{timestamp: "2018-12-09T16:00:00.000", count: 0}], second: [{timestamp: "2018-12-09T17:00:00.000", count: 0}], third: [{timestamp: "2018-12-09T18:00:00.000", count: 3}]}

(object1并且object2可能有长度 > 1 的数组,例如:

const object1 = {first: [{timestamp: "2018-12-09T16:00:00.000", count: 3}, {timestamp: "2018-12-09T16:30:00.000", count: 5}], second: [{timestamp: "2018-12-09T17:00:00.000", count: 2}], third: [{timestamp: "2018-12-09T18:00:00.000", count: 2}]}
const object2 = {first: [{timestamp: "2018-12-09T16:00:00.000", count: 0}, {timestamp: "2018-12-09T16:30:00.000", count: 0}], second: [{timestamp: "2018-12-09T17:00:00.000", count: 0}], third: [{timestamp: "2018-12-09T18:00:00.000", count: 3}]}

)

我想要一个相同格式的对象,但是:

所以预期的结果是:

const res = {first: [{timestamp: 2018-12-09T16:00:00.000, count: 3}], second: [{timestamp: 2018-12-09T17:00:00.000, count: 2}], third: [{timestamp: 2018-12-09T18:00:00.000, count: 5}]}

(如果object1并且object2数组的长度> 1:

const res = {first: [{timestamp: 2018-12-09T16:00:00.000, count: 3}, {timestamp: "2018-12-09T16:30:00.000", count: 5}], second: [{timestamp: 2018-12-09T17:00:00.000, count: 2}], third: [{timestamp: 2018-12-09T18:00:00.000, count: 5}]}

)

mergeWith以这种方式使用了 Lodash:

const merged = _.mergeWith(object1, object2, (objValue, srcValue) => [
  { count: objValue[0].count + srcValue[0].count },
])
const r = Object.entries(merged).map(([key, value], i) => {
  return { number: key, timestamp: value.map(convertTimestamp) }
})
console.log('r: ', r)

哪里convertTimestamp是:

const convertTimestamp = (d) => ({
  ...d,
  timestamp: new Date(d.timestamp),
})

这是结果:

[
  {
    "number": "first",
    "timestamp": [
      {
        "count": 3,
        "timestamp": null
      }
    ]
  },
  {
    "number": "second",
    "timestamp": [
      {
        "count": 2,
        "timestamp": null
      }
    ]
  },
  {
    "number": "third",
    "timestamp": [
      {
        "count": 5,
        "timestamp": null
      }
    ]
  }
]

显然它不起作用。它有3个问题:

  1. 没有正确值的嵌套对象
  2. 时间戳不正确
  3. ifobject1object2具有相同的密钥,但如果它们是:

const object1 = {first: [{timestamp: "2018-12-09T16:00:00.000", count: 3}], second: [{timestamp: "2018-12-09T17:00:00.000", count: 2}], third: [{timestamp: "2018-12-09T18:00:00.000", count: 2}]}

const object2 = {second: [{timestamp: "2018-12-09T17:00:00.000", count: 0}], third: [{timestamp: "2018-12-09T18:00:00.000", count: 3}]}

(缺少object2 first),该程序不起作用...

我需要帮助

这是一个可测试的代码:

function mergeData(object1, object2) {
  const merged = _.mergeWith(object1, object2, (objValue, srcValue) => [
    { count: objValue[0].count + srcValue[0].count},
  ])
  const r = Object.entries(merged).map(([key, value], i) => {
    return { number: key, timestamp: value.map(convertTimestamp) }
  })
  return r
}

const convertTimestamp = (d) => {
  return ({
    ...d,
    timestamp: new Date(d.timestamp),
  })
}

const object1 = {first: [{timestamp: "2018-12-09T16:00:00.000", count: 3}], second: [{timestamp: "2018-12-09T17:00:00.000", count: 2}], third: [{timestamp: "2018-12-09T18:00:00.000", count: 2}]}
const object2 = {first: [{timestamp: "2018-12-09T16:00:00.000", count: 0}], second: [{timestamp: "2018-12-09T17:00:00.000", count: 0}], third: [{timestamp: "2018-12-09T18:00:00.000", count: 3}]}


const result = mergeData(object1, object2)
console.log(result)
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>


一些例子:

// example 1
const object1 = {
  first: [{timestamp: "2018-12-09T16:00:00.000", count: 3}, {timestamp: "2018-12-09T16:30:00.000", count: 5}], 
  second: [{timestamp: "2018-12-09T17:00:00.000", count: 2}], 
  third: [{timestamp: "2018-12-09T18:00:00.000", count: 2}]
}
const object2 = {
  first: [{timestamp: "2018-12-09T16:00:00.000", count: 0}, {timestamp: "2018-12-09T16:30:00.000", count: 0}], 
  second: [{timestamp: "2018-12-09T17:00:00.000", count: 0}], 
  third: [{timestamp: "2018-12-09T18:00:00.000", count: 3}]
}

const result = {
  first: [{timestamp: "2018-12-09T16:00:00.000", count: 3}, {timestamp: "2018-12-09T16:30:00.000", count: 5}], 
  second: [{timestamp: "2018-12-09T17:00:00.000", count: 2}], 
  third: [{timestamp: "2018-12-09T18:00:00.000", count: 5}]
}


// example 2
const object1 = {
  first: [{timestamp: "2018-12-09T16:00:00.000", count: 3}, {timestamp: "2018-12-09T16:30:00.000", count: 5}], 
  second: [{timestamp: "2018-12-09T17:00:00.000", count: 2}], 
  third: [{timestamp: "2018-12-09T18:00:00.000", count: 2}]
}
const object2 = {
  first: [{timestamp: "2018-12-09T16:00:00.000", count: 0}], 
  second: [{timestamp: "2018-12-09T17:00:00.000", count: 0}], 
  third: [{timestamp: "2018-12-09T18:00:00.000", count: 3}]
}

const result = {
  first: [{timestamp: "2018-12-09T16:00:00.000", count: 3}, {timestamp: "2018-12-09T16:30:00.000", count: 5}], 
  second: [{timestamp: "2018-12-09T17:00:00.000", count: 2}], 
  third: [{timestamp: "2018-12-09T18:00:00.000", count: 5}]
}


// example 3
const object1 = {
  first: [{timestamp: "2018-12-09T16:00:00.000", count: 3}, {timestamp: "2018-12-09T16:30:00.000", count: 5}], 
  second: [{timestamp: "2018-12-09T17:00:00.000", count: 2}], 
  third: [{timestamp: "2018-12-09T18:00:00.000", count: 2}]
}
const object2 = {
  second: [{timestamp: "2018-12-09T17:00:00.000", count: 0}], 
  third: [{timestamp: "2018-12-09T18:00:00.000", count: 3}]
}

const result = {
  first: [{timestamp: "2018-12-09T16:00:00.000", count: 3}, {timestamp: "2018-12-09T16:30:00.000", count: 5}], 
  second: [{timestamp: "2018-12-09T17:00:00.000", count: 2}], 
  third: [{timestamp: "2018-12-09T18:00:00.000", count: 5}]
}


// example 4
const object1 = {
  first: [{timestamp: "2018-12-09T16:00:00.000", count: 3}, {timestamp: "2018-12-09T16:30:00.000", count: 5}], 
  second: [{timestamp: "2018-12-09T17:00:00.000", count: 2}, {timestamp: "2018-12-09T17:30:00.000", count: 20}, {timestamp: "2018-12-09T18:00:00.000", count: 10}], 
  third: [{timestamp: "2018-12-09T18:00:00.000", count: 2}]
}
const object2 = {
  first: [{timestamp: "2018-12-09T16:00:00.000", count: 0}, {timestamp: "2018-12-09T16:30:00.000", count: 0}], 
  second: [{timestamp: "2018-12-09T17:00:00.000", count: 0}, {timestamp: "2018-12-09T17:30:00.000", count: 6}, {timestamp: "2018-12-09T18:00:00.000", count: 2}], 
  third: [{timestamp: "2018-12-09T18:00:00.000", count: 3}]
}

const result = {
  first: [{timestamp: "2018-12-09T16:00:00.000", count: 3}, {timestamp: "2018-12-09T16:30:00.000", count: 5}], 
  second: [{timestamp: "2018-12-09T17:00:00.000", count: 2}, {timestamp: "2018-12-09T17:30:00.000", count: 26}, {timestamp: "2018-12-09T18:00:00.000", count: 12}], 
  third: [{timestamp: "2018-12-09T18:00:00.000", count: 5}]
}

标签: javascriptlodash

解决方案


从可读性的角度来看,将其分解为更小的问题可能更容易。例如,您需要能够在日期上合并子数组,并且您还需要为每个对象中的不同键集做好准备。

这解决了每一个问题:

const object1 = {first: [{timestamp: "2018-12-09T16:00:00.000", count: 3}], second: [{timestamp: "2018-12-09T17:00:00.000", count: 2}], third: [{timestamp: "2018-12-09T18:00:00.000", count: 2}]}
const object2 = {first: [{timestamp: "2018-12-09T16:00:00.000", count: 0}], second: [{timestamp: "2018-12-09T17:00:00.000", count: 0}], third: [{timestamp: "2018-12-09T18:00:00.000", count: 3}]}

// a function to merge arrays with defaulf values
// in  case one is not defined
function mergeArray(a1 =[], a2 =[]){
    let hash  = [...a1, ...a2].reduce((hash, {timestamp, count}) =>{
        if(!hash.hasOwnProperty(timestamp)) hash[timestamp] = {timestamp, count:0}
        hash[timestamp].count += count
        return hash
    }, {})
    return Object.values(hash)
}

// a set of all keys between the tow objects
// so the objects don't nees to have the same keys
// we'll loop over this to make sure we get everything
const allKeys = new Set([...Object.keys(object1), ...Object.keys(object2)])

// now for each known key merge the arrays
let res = {}
for (key of allKeys){
    res[key] = mergeArray(object1[key], object2[key])
}
console.log(res)


推荐阅读