JavaScript-“合并”两个类似的对象数组

时间:2019-01-13 19:36:28

标签: javascript arrays node.js mapreduce

假设我有以下两个数组:

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(),但这似乎不是答案(除非我错了)。我该怎么办?

2 个答案:

答案 0 :(得分:2)

您可以从第二个数组的对象中创建一个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);

答案 1 :(得分:0)

您可以尝试的一种解决方案是Webworkers。如果您以前从未使用过它们,则它们可以在单独的线程中运行脚本,从本质上讲,您可以使用多个内核来处理某些事情。它们非常适合可并行化的任务,这意味着可以分解而没有任何中断的任务。它们将非常适合您的用例,因为您只是对数据做一个大的映射。

在走这条路之前,尽管应该警告您Web工作者有一些开销。为了使数据进入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}})的结果。

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