javascript - 数组的高效映射

标签 javascript arrays dictionary functional-programming

我正在尝试找出在 JS 中同时比较/合并/操作两个数组(列表)的最佳/最有效或最实用的方法。

我下面给出的例子是整体概念的一个简单例子。在我当前的项目中,我使用非常大的对象列表处理一些非常疯狂的列表映射、过滤等。

如下所述,我关于比较列表的第一个想法(version1)是遍历第一个列表(即 map),并在匿名/回调函数中过滤第二个列表以满足比较所需的标准(例如匹配 ID)。根据下面的 version1,这显然有效。

我有一个性能方面的问题,因为通过这种方法在 map 的每次迭代/调用中,整个第二个列表都会被过滤,只是为了找到与过滤器匹配的项目。

Also, the filter passes every other item in list2 which should be matched in list1. Meaning (as that sentence probably did not make sense):

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

Ideally on the first iteration of map (list1 id:1), when the filter encounters list2 id:3 (first item) it would just match it to list1 id:3

想到上面的概念(前面遇到的id匹配后面的id,就想到了version2)。

这样就把list2变成了一个字典,然后key查找任意序列中的值。

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)。我正在处理更复杂的实例。

我不知道是否有一些我应该使用的更智能(和理想功能)的技术。

最佳答案

您可以关闭组所需的 key 和 Map用于收集所有对象。

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; }

关于javascript - 数组的高效映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55966307/

相关文章:

C++ 二维数组不显示

java - 使用多个数组列表或带有 stringtokenizer 的数组在 java 中编写解释器

ios - 如何知道我的数组是否包含字典?

python - 在数据框列中查找字典的值并修改它

ios - 如何将对象设置为 plist 文件中的嵌套字典或数组

javascript - 同步加载 HTML 内容

javascript - CSS 模块在 Codesandbox 中不起作用 - 即使文件存在也无法找到

c++ - 使用指针相乘矩阵

javascript - 从 JavaScript 代码执行 Genexus 的事件

javascript - MVC - 更改下拉选择上的标签 - 强类型 View