【问题标题】:Merge two n number of array of objects based on a key根据一个键合并两个 n 个对象数组
【发布时间】:2021-02-17 06:26:57
【问题描述】:

我有两个数组:

数组 1:

[
    {old_clicks: 1, date: "2017-01-24" }, 
    { old_clicks: 4, date: "2017-01-22" },
    { old_clicks: 6, date: "2017-01-21" }
]

和数组 2:

[
    { total_clicks:120, date: "2017-01-21" },
    { total_clicks: 100, date: "2017-01-19" }
]

我需要基于date合并这两个数组并得到这个:

[
    { old_clicks: 1,date: "2017-01-24", total_clicks: 0 },
    { old_clicks: 4, date: "2017-01-22", total_clicks: 0 },
    { old_clicks: 6, date: "2017-01-21", total_clicks: 120 },
    { old_clicks: 0, date: "2017-01-19", total_clicks: 100 },
]

我已经尝试过了,但是由于它没有正确合并,所以它不起作用。

const arr1 = [
    { old_clicks: 1, date: "2017-01-24" }, 
    { old_clicks: 4, date: "2017-01-22" },
    { old_clicks: 6, date: "2017-01-21" }
];


const arr2 =  [
    { total_clicks:120, date: "2017-01-21" },
    { total_clicks: 100, date: "2017-01-19" }
];
        

const mergeById = (a1, a2) => a1.map(itm => ({
    ...a2.find((item) => (item.date=== itm.date)),
    ...itm
}));

console.log(mergeById(arr1,arr2))

【问题讨论】:

  • @mplungjan 请查看两个数组,因为日期不在第一个数组上,但在第二个数组上。
  • @mplungjan 我在代码中进行了编辑以匹配 &item,谢谢指出
  • 是的,打错字了,对不起

标签: javascript arrays javascript-objects


【解决方案1】:

这看起来像是 Array.reduce 的案例。

reduce() 方法对数组的每个元素执行(您提供的)reducer 函数,从而产生单个输出值。

签名是:

arr.reduce(callback( accumulator, currentValue, [, index[, array]] )[, initialValue])

这里的方法是使用它们的date 属性将项目添加到一个“地图”对象的键中,该对象开始初始化为一个空对象,然后在您关心的点击属性中求和。最后,result 将成为一个对象,我们可以使用Object.values() 将其值转换为数组。我们选择在内部使用一个对象来更快地查找现有日期,您可以减少使用数组来代替,但天真地使用 arr.find 会为您提供 O(n2) 解决方案。

const arr1 = [
  { old_clicks: 1, date: "2017-01-24" },
  { old_clicks: 4, date: "2017-01-22" },
  { old_clicks: 6, date: "2017-01-21" }
];


const arr2 = [
  { total_clicks: 120, date: "2017-01-21" },
  { total_clicks: 100, date: "2017-01-19" }
];


const mergeById = (...arrs) => {

  const result = arrs.flat().reduce((acc, obj) => {
    acc[obj.date] = {
      date: obj.date,
      total_clicks: (acc[obj.date]?.total_clicks ?? 0) + (obj?.total_clicks ?? 0),
      old_clicks: (acc[obj.date]?.old_clicks ?? 0) + (obj?.old_clicks ?? 0),
    }

    return acc;
  }, {})
  
  return Object.values(result);
}

console.log(mergeById(arr1, arr2))

【讨论】:

  • 我也喜欢obj?.total_clicks ?? 0 - 我用?.|| 但你的更安全
  • 其实我今天才学obj?.prop ?? default
  • 我也是 :) nullish coalescing operator 结合 optional chaining - 我知道第一个并使用了第二个,但组合很酷
【解决方案2】:

这是一个非常简单的实现,它使用一个对象作为中间映射,并使用 Object.assign 来处理属性合并。

此实现支持任意数量的输入数组进行合并,并且还自动支持任何附加属性。

它与您的示例无关,它是解决如何按键将对象数组合并在一起的问题的通用解决方案。

请注意,如果 arr1 和 arr2 都定义了相同的属性(如 old_clicks),则最新的将获胜。这可能是也可能不是您想要的(您可能想将它们加在一起?)

const arr1 = [
    { old_clicks: 1, date: "2017-01-24" },
    { old_clicks: 4, date: "2017-01-22" },
    { old_clicks: 6, date: "2017-01-21" }
];

const arr2 = [
    { total_clicks: 120, date: "2017-01-21" },
    { total_clicks: 100, date: "2017-01-19" }
];

function mergeByProperty(mergeProperty, defaults, ...arraysToMerge) {
    const mergeObj = {};

    arraysToMerge.forEach(function (arrayToMerge) {
        arrayToMerge.forEach(function (item) {
            const mergeValue = item[mergeProperty];

            if (mergeValue) {
                if (!mergeObj[mergeValue]) {
                    mergeObj[mergeValue] = Object.assign({}, defaults, item);
                }
                else {
                    Object.assign(mergeObj[mergeValue], item);
                }
            }
            else {
                // TODO Invalid item.  Throw an Error or skip it.
            }
        });
    });

    return Object.values(mergeObj);
}

function mergeByDate(...arraysToMerge) {
    return mergeByProperty("date", { old_clicks: 0, total_clicks: 0 }, ...arraysToMerge);
}

console.log(mergeByDate(arr1, arr2));

【讨论】:

    猜你喜欢
    • 2022-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-16
    • 1970-01-01
    • 1970-01-01
    • 2021-09-12
    相关资源
    最近更新 更多