首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >阵列的有效映射

阵列的有效映射
EN

Stack Overflow用户
提问于 2019-05-03 08:50:08
回答 4查看 116关注 0票数 3

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

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

如下所示,我关于比较列表的第一个想法(version1)是通过第一个列表(即地图)运行,并且在匿名/回调函数中,筛选第二个列表以满足比较所需的条件(例如匹配ids )。这显然是可行的,正如下面的version1所示。

我有一个关于性能的问题,因为在每次地图的迭代/调用中,都会对整个第二个列表进行过滤,以找到一个与过滤器匹配的项。

此外,过滤器传递list2中应该在list1中匹配的所有其他项。意思(因为这句话可能没有意义): 列表1.映射列表2.过滤器id:1 id:3,id:2,id:1 ^-匹配id:2,id:1,id:3,id:2,id:1 ^-匹配 理想情况下,在映射(list1 id:1)的第一次迭代中,当筛选器遇到list2 id:3 (第一项)时,它将只与list1 id:3匹配。

考虑到上面的概念(当前面遇到一个更晚的id时,我想到了version2)。

这使list2成为一个字典,然后按键查找任意序列中的值。

代码语言:javascript
复制
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)。还有更复杂的例子,我正在工作。

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

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2019-05-03 09:00:11

您可以在组的“希望”键上选择一个闭包,并为收集所有对象而使用一个Map

代码语言:javascript
复制
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);
代码语言:javascript
复制
.as-console-wrapper { max-height: 100% !important; top: 0; }

票数 3
EN

Stack Overflow用户

发布于 2019-05-04 01:14:40

使用filter进行搜索是一个错误。你在第2版中的直觉要好得多。MapSet提供了更快的查找时间。

这是一个分解的方法。它应该很快,但可能不如妮娜的那么快。她是一个速度恶魔>_<

代码语言:javascript
复制
const merge = (...lists) =>
  Array .from
    ( lists
        .reduce (merge1, new Map)
        .values ()
    )

const merge1 = (cache, list) =>
  list .reduce
    ( (cache, l) =>
        cache .has (l.id)
          ? update (cache, l.id, l)
          : insert (cache, l.id, l)
    , cache
    )

const insert = (cache, key, value) =>
  cache .set (key, value)

const update = (cache, key, value) =>
  cache .set
    ( key
    , { ...cache .get (key)
      , ...value
      }
    )

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' }]

console .log (merge (list1, list2))

票数 1
EN

Stack Overflow用户

发布于 2019-05-04 02:10:10

我提供这是为了完整,因为我认为Nina和@ more 633183提供了最有可能更有效的解决方案。

如果您希望坚持您的初始筛选示例,这是一个最大查找N*M,并且您的数组是可变的;您可以考虑在遍历时减少集合。在过去,数组的缩小对性能产生了巨大的影响。

今天的一般模式是使用Map (或dict),如其他答案所示,因为它既容易理解,又通常有效。

查找和调整大小

代码语言:javascript
复制
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'}
];

// combine by ID
let merged = list1.reduce((acc, obj)=>{
  acc.push(obj);

  // find index by ID
  let foundIdx = list2.findIndex( el => el.id==obj.id );
  // if found, store and remove from search
  if ( foundIdx >= 0 ){
    obj.data = list2[foundIdx].data;
    list2.splice( foundIdx, 1 );        // shrink lookup array
  }
  return acc;
},[]);

// store remaining (if you want); i.e. {id:4,data:'data4'}
merged = merged.concat(list2)

console.log(merged);
代码语言:javascript
复制
.as-console-wrapper {
  max-height: 100% !important;
  top: 0;
}

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55966307

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档