【问题标题】:JavaScript - "Combining" two similar arrays of objectsJavaScript - “组合”两个相似的对象数组
【发布时间】:2019-01-13 19:36:27
【问题描述】:

假设我有以下两个数组:

let arr1 = [ { id: "1234567890", name: "Someone", other: "unneeded", props: 123 } ... ];
let arr2 = [ { id: "1234567890", points: 100, other: "unneeded", props: 456 } ... ];

我需要根据 id 的名称和点数将它们组合起来,如下所示:

[ { id: "1234567890", name: "Someone", points: 100 } ... ]

一种选择是像这样映射它们:

let final = arr1.map(u => ({
    id: u.id,
    name: u.name,
    points: arr2.find(uu => uu.id === u.id)
}));

但是,这对于较大的数组(数千个条目)来说效率很低,因为find() 每次都会遍历数组。我正在努力提高效率。我阅读了Array.reduce(),但这似乎不是答案(除非我错了)。我该怎么做?

【问题讨论】:

  • 这里的组合逻辑是什么?
  • @Ashish 如最终数组的示例所示,我想通过id“合并”namepoints
  • id 总是整数吗?
  • @TommiTuura 已编辑,应该是一个字符串,但是是的,它永远是一个字符串

标签: javascript arrays node.js mapreduce


【解决方案1】:

你可以从第二个数组的对象中创建一个Map,这样你就可以在常量时间内通过id直接访问对应的对象:

let arr1 = [
  {id: 1234567890, name: "Someone", other: "unneeded", props: 123},
  {id: 1234567891, name: "Someone1", other: "unneeded1", props: 124},
  {id: 1234567892, name: "Someone2", other: "unneeded2", props: 125}
];
let arr2 = [
  {id: 1234567890, points: 100, other: "unneeded", props: 456},
  {id: 1234567891, points: 101, other: "unneeded", props: 457},
  {id: 1234567892, points: 102, other: "unneeded", props: 458}
];

let arr2Map = arr2.reduce((a, c) => {
  a.set(c.id, c);
  return a;
}, new Map());

let final = arr1.map(({id, name, points}) => 
  ({id, name, points: arr2Map.get(id).points || points}));

console.log(final);

【讨论】:

    【解决方案2】:

    您可以尝试的一个解决方案是Webworkers。如果您以前没有使用过它们,它们可以在单独的线程中运行脚本,本质上允许您使用多个内核来处理某些东西。它们非常适合可并行化的任务,这意味着可以在没有任何中断的情况下分解任务。它们非常适合您的用例,因为您只是在数据上绘制大地图。

    在走这条路之前,你应该预先警告网络工作者有一些开销。为了将数据输入 webworker,您必须将其序列化到线程中,然后在返回时反序列化它。但是,如果您将任务拆分为单独的工作并让它们并行运行,您应该能够减轻其中的一些影响。

    // app.js
    let largeArray = []; // contains the large amount of arrays to map
    let outputArray = []; 
    while(largeArray.length){
        let worker = new Worker('/path/to/worker/script.js');
        worker.postMessage({
            chunk: largeArray.splice(0,1000)
        });
        worker.onmessage = evt => {
            let data = evt.data;
            outputArray = outputArray.concat(data);
            worker.terminate();
        }
    }
    

    单独有一个工作脚本,可能与这个类似,可供参考。

    // workerScript.js
    self.onmessage = ({data: {chunk}}) => {
        let final = chunk.map(u => ({
            id: u.id,
            name: u.name,
            points: arr2.find(uu => uu.id === u.id)
        }));
        self.postMessage(final);
    }
    

    您可能会询问有关序列化的问题,这是自动发生的事情。 Webworkers 有自己的全局作用域,作为序列化的结果,您可以发送对象、数组和原语。所有这些都可以序列化。但是,具有自定义属性和类的对象会抛出错误。在幕后,它基本上是获取您的数据并执行JSON.stringify({{your data}}),然后在 webworker 中数据成为JSON.parse({{serialized data}}) 的结果。

    由于这项工作是在单独的线程中进行的,因此您不会在应用运行的主线程上看到任何阻塞。但是,如果您尝试一次处理太多,则序列化会很明显,因为它会一直阻塞直到完成。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-12-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-04
      • 2016-11-12
      • 1970-01-01
      相关资源
      最近更新 更多