JavaScript - "Combining" 两个相似的对象数组
JavaScript - "Combining" two similar arrays of objects
假设我有以下两个数组:
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()
,但这似乎不是答案(除非我错了)。我该怎么做?
可以从第二个数组的对象中创建一个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);
您可以尝试的一种解决方案是 Webworkers。如果您以前没有使用过它们,它们可以 运行 在单独的线程中编写脚本,基本上允许您使用多个内核来处理某些事情。它们非常适合可并行化的任务,这意味着可以在没有任何中断的情况下分解的任务。它们非常适合您的用例,因为您只是在数据上绘制大地图。
在走这条路之前,你应该预先警告 webworkers 有一些开销。为了将数据放入 webworker 中,您必须将其序列化到线程中,然后在 returns 时将其反序列化。但是,如果您将任务拆分为单独的工作并让它们并行运行,您应该能够减轻其中的一些影响。
// 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();
}
}
另外有一个worker脚本,可能跟这个差不多,可以参考。
// 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);
}
您可能会问序列化,这是自动发生的事情。 Webworker 有自己的全局范围,作为序列化的结果,您可以发送对象、数组和原语。所有这些都可以序列化。具有自定义属性和 类 的对象会抛出错误。在幕后,它基本上是获取您的数据并执行 JSON.stringify({{your data}})
,然后在 webworker 数据中成为 JSON.parse({{serialized data}})
.
的结果
因为这项工作是在单独的线程中进行的,所以您不会在应用 运行ning 所在的主线程上看到任何阻塞。但是,如果您尝试一次处理太多,那么序列化会很明显,因为它在完成之前一直处于阻塞状态。
假设我有以下两个数组:
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()
,但这似乎不是答案(除非我错了)。我该怎么做?
可以从第二个数组的对象中创建一个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);
您可以尝试的一种解决方案是 Webworkers。如果您以前没有使用过它们,它们可以 运行 在单独的线程中编写脚本,基本上允许您使用多个内核来处理某些事情。它们非常适合可并行化的任务,这意味着可以在没有任何中断的情况下分解的任务。它们非常适合您的用例,因为您只是在数据上绘制大地图。
在走这条路之前,你应该预先警告 webworkers 有一些开销。为了将数据放入 webworker 中,您必须将其序列化到线程中,然后在 returns 时将其反序列化。但是,如果您将任务拆分为单独的工作并让它们并行运行,您应该能够减轻其中的一些影响。
// 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();
}
}
另外有一个worker脚本,可能跟这个差不多,可以参考。
// 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);
}
您可能会问序列化,这是自动发生的事情。 Webworker 有自己的全局范围,作为序列化的结果,您可以发送对象、数组和原语。所有这些都可以序列化。具有自定义属性和 类 的对象会抛出错误。在幕后,它基本上是获取您的数据并执行 JSON.stringify({{your data}})
,然后在 webworker 数据中成为 JSON.parse({{serialized data}})
.
因为这项工作是在单独的线程中进行的,所以您不会在应用 运行ning 所在的主线程上看到任何阻塞。但是,如果您尝试一次处理太多,那么序列化会很明显,因为它在完成之前一直处于阻塞状态。