javascript - 高效的数组映射
问题描述
我试图找出在 JS 中同时比较/合并/操作两个数组(列表)的最佳/最有效或最实用的方法。
我在下面给出的示例是整体概念的一个简单示例。在我当前的项目中,我处理了一些非常疯狂的列表映射、过滤等,其中包含非常大的对象列表。
如下所述,我version1
对比较列表的第一个想法( )。这显然有效,version1
如下所示。
我有一个性能方面的问题,因为在每次迭代/调用 map 时通过这种方法,整个第二个列表都会被过滤,只是为了找到一个与过滤器匹配的项目。
此外,过滤器通过 list2 中应在 list1 中匹配的所有其他项目。含义(因为那句话可能没有意义):
list1.map list2.filter id:1 [id:3,id:2,id:1] ^-match id:2 [id:3,id:2,id:1] ^-match id:3 [id:3,id:2,id:1] ^-match
理想情况下,在 map (
list1 id:1
) 的第一次迭代中,当过滤器遇到list2 id:3
(第一项)时,它只会将其匹配到list1 id:3
用上面的概念思考(前面遇到的时候匹配后面的id,我想出了version2
)。
这使得 list2 成为一个字典,然后通过键以任何顺序查找值。
const list1 = [
{id: '1',init:'init1'},
{id: '2',init:'init2'},
{id: '3',init:'init3'}
];
const list2 = [
{id: '2',data:'data2'},
{id: '3',data:'data3'},
{id: '4',data:'data4'}
];
/* ---------
* version 1
*/
const mergedV1 = list1.map(n => (
{...n,...list2.filter(f => f.id===n.id)[0]}
));
/* [
{"id": "1", "init": "init1"},
{"id": "2", "init": "init2", "data": "data2"},
{"id": "3", "init": "init3", "data": "data3"}
] */
/* ---------
* version 2
*/
const dictList2 = list2.reduce((dict,item) => (dict[item.id]=item,dict),{});
// does not handle duplicate ids but I think that's
// outside the context of this question.
const mergedV2 = list1.map(n => ({...n,...dictList2[n.id]}));
/* [
{"id": "1", "init": "init1"},
{"id": "2", "init": "init2", "data": "data2"},
{"id": "3", "init": "init3", "data": "data3"}
] */
JSON.stringify(mergedV1) === JSON.stringify(mergedV2);
// true
// and just for fun
const sqlLeftOuterJoinInJS = list1 => list2 => on => {
const dict = list2.reduce((dict,item) => (
dict[item[on]]=item,dict
),{});
return list1.map(n => ({...n,...dict[n[on]]}
))};
显然上面的例子非常简单(合并两个列表,每个列表的长度为 3)。我正在处理更复杂的实例。
我不知道是否有一些我应该使用的更智能(并且功能理想)的技术。
解决方案
您可以关闭该组的所需密钥和Map
收集所有对象的 a。
function merge(key) {
var map = new Map;
return function (r, a) {
a.forEach(o => {
if (!map.has(o[key])) r.push(map.set(o[key], {}).get(o[key]));
Object.assign(map.get(o[key]), o);
});
return r;
};
}
const
list1 = [{ id: '1', init: 'init1' }, { id: '2', init: 'init2' }, { id: '3', init: 'init3' }],
list2 = [{ id: '2', data: 'data2' }, { id: '3', data: 'data3' }, { id: '4', data: 'data4' }],
result = [list1, list2].reduce(merge('id'), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
推荐阅读
- neo4j - 没有名称为 apoc.refactor.cloneSubgraphfrompaths 的过程为此数据库实例注册
- react-native - 减少水平滚动视图中图像的大小 React native
- python - 值错误:预期输入数据 X 有 1 个特征,但在高斯混合模型中得到 2 个特征
- python - 为什么我在使用 sympy.dsolve 时得到“'list' object has no attribute 'func'”?
- graphql - Graphql 联合与模式拼接。何时选择一个而不是另一个
- c# - 引用另一个项目的问题
- android - 尝试在后台执行操作时出现 MissingPluginException
- reactjs - 避免在创建反应应用程序中从公共目录缓存工作文件
- node.js - 如果 Promise 永远运行,Node.JS 会发生什么?
- python - 有没有办法以简单的方式重复代码?