Javascript 根据id从另一个数组中分配一些字段,并根据值类型获得最终输出?

Javascript 根据id从另一个数组中分配一些字段,并根据值类型获得最终输出?,javascript,arrays,node.js,performance,functional-programming,Javascript,Arrays,Node.js,Performance,Functional Programming,我想根据id值将字段“type”和“publisher”分配给arr1,同时我想根据类型分配数组 所需的输出是 arr1 = [ { id : 1, name : 'book1', description: 'some text' }, { id : 2, name : 'book2', description: 'some text'

我想根据id值将字段“type”和“publisher”分配给arr1,同时我想根据类型分配数组

所需的输出是

arr1 = [ 
         { id : 1,
           name : 'book1',
           description: 'some text'
         },
         { id : 2,
           name : 'book2',
           description: 'some text'
         },
         { id : 3,
           name : 'book3',
           description: 'some text'
         }
       ]

arr2 = [ 
         { id : 1,
           name : 'book1',
           type : 'thriller',
           publisher : 'some x',
           isbn : '2983457928435',
           date : '20-1-2014'
         },
         { id : 2,
           name : 'book2',
           type : 'action',
           publisher : 'some x',
           isbn : '2983457928435',
           date : '20-1-2014'
         },
         { id : 3,
           name : 'book3',
           type : 'thriller',
           publisher : 'some y',
           isbn : '2983457928435',
           date : '20-1-2014'
         }
       ]
性能是关键问题。我可以实现以上一个使用2个功能,但我想实现它在单一的功能

Edit1:-在arr1中,我从数据库(mongodb)中获得了一些其他字段以及上述字段。为了简单起见,我已经包括了任何必要的东西

目前,我通过以下两个功能来实现这一点

职能1:-

arr3 = { 
   'thriller': [
     { id: 1, name: 'book1', type: 'thriller', publisher: 'some x', description: 'some text' }, 
     { id: 3, name: 'book3', type: 'thriller', publisher: 'some y', description: 'some text' }
   ], 
   'action': [
     { id: 2, name: 'book2', type: 'action', publisher: 'some x', description: 'some text' }] 
 }
职能2:-

let result = arr1.map((e) => {
        for(let element of arr2){
            if(e.id === element.id)
              { 
                e['type'] = element.type
                e['publisher'] = element.publisher
              }
        }
        return e
      })
我想要的是将这两种功能结合起来,并在单个函数调用中执行。

arr1=[
{id:1,
名称:'book1',
描述:'此处有一些文字'
},
{id:2,
名称:'book2',
描述:'此处有一些文字'
},
{id:3,
名称:'book3',
描述:'此处有一些文字'
}
]
arr2=[
{id:1,
名称:'book1',
类型:“thriller”,
出版商:“一些x”
},
{id:2,
名称:'book2',
键入:“操作”,
出版商:“一些x”
},
{id:3,
名称:'book3',
类型:“thriller”,
出版者:“一些y”
}
]
让结果=arr1.减少(功能(acc,e){
for(arr2的let元素){
if(e.id==element.id)
{ 
e['type']=element.type
e['publisher']=element.publisher
打破
}
}
var key=e['type'];
如果(!acc[键]){
acc[键]=[];
}
acc[键]。按下(e);
返回acc;
}, {});

console.log(result)
一旦执行此操作,我可以想象您将遇到的唯一值得注意的性能问题就会出现:

function groupBy(objectArray, property) {
  return objectArray.reduce(function (acc, obj) {
    var key = obj[property];
    if (!acc[key]) {
      acc[key] = [];
    }
    acc[key].push(obj);
    return acc;
  }, {});
}

let output = groupBy(result, 'type');
这种嵌套循环大大增加了迭代次数。对于
arr1
的每个元素,我们(可能)循环了
arr2
的每个元素,给出了
arr1.length
(最佳情况)和
arr1.length*arr2.length
(最坏情况)之间的迭代次数。如果您使用的是真正的大数据集,那么这种差异可能很明显

通常,解决方案是将数组索引到对象或贴图中,这样可以更快地查找。转换阵列需要一些时间,但是循环运行得更快

以下是我的建议:

  • arr1
    转换为以下形式的索引
    bookscriptions
    {id:{name,id,description}}
  • arr2
    转换为以下格式的索引
    bookMetadata
    {id:{name,id,type,publisher}
  • 列出
    书籍
    dat将这些按id合并到:
    [{name,id,type,description,publisher}]
  • 使用您的
    groupBy
    进行最终分组
  • 代码:

    //按唯一属性对值数组进行索引
    常数indexBy=(k,xs)=>xs.reduce(
    (acc,x)=>Object.assign(acc,{[x[k]]:x}),
    {}
    );
    //按特定属性对对象数组进行分组
    常量groupBy=(k,xs)=>xs.reduce(
    (acc,x)=>Object.assign(acc,{
    [x[k]]:附件[x[k]]
    ?附件[x[k].混凝土(x)
    :[x]
    }), 
    {}
    );
    //返回不带重复项的数组
    const uniques=xs=>Array.from(新集合(xs));
    //使用Object.assign按索引键合并两个索引
    常量合并索引=(i1,i2)=>
    独特的([
    …对象键(i1),
    …对象.键(i2)
    ]).map(k=>Object.assign({},i1[k],i2[k]);
    const bookscriptions=indexBy(“id”,getDescriptions());
    const bookmatadata=indexBy(“id”,getMetadata());
    const books=合并索引(图书描述、图书元数据);
    const booksByType=groupBy(“type”,books);
    console.log(booksByType);
    函数getDescriptions(){return[{id:1,name:“book1”,description:“some text”},{id:2,name:“book2”,description:“some text”},{id:3,name:“book3”,description:“some text”};};
    
    函数getMetadata(){return[{id:1,name:“book1”,type:“thriller”,publisher:“some x”},{id:2,name:“book2”,type:“action”,publisher:“some x”},{id:3,name:“book3”,type:“thriller”,publisher:“some y”}
    你能提供你正在使用的两个函数吗?
    但我想用一个函数来实现它。
    为什么?调用函数不会影响性能。那你为什么需要
    arr1
    呢?@离开我的草坪,@Jonas W,看看Edit1I我同意你的观点“arr1.length(最佳情况)和arr1.length*arr2.length(最坏情况)”。但在我的真实案例中,在arr2以及类型和发布者字段中,我有一些其他文件,我不希望它们出现在最终输出中,这是我只能分配类型和发布者字段的方式。你能给我建议一些其他更好的方法来省略for循环,然后if条件吗?因为我只需要type和publisher字段,但arr2包含一些其他额外字段。此函数是当前的合并逻辑:
    k=>Object.assign({},i1[k],i2[k])
    。您可以手动创建一个新对象。例如:
    k=>({id:i1[k].id,type:i2[k].type})
    在上述功能中,它必须循环数组以分配和追加字段。这个假设正确吗?我已经测试了你的代码在数组中的长度为18项,并比较了计算时间,这需要一些额外的时间。我编写的代码在18项中不会更快。。。当你说你担心性能时,我以为你说的更像是1000件物品;)尝试100、1000和10000,看看是否有不同……我看你已经接受了自己的答案,其中没有包括与原始问题不同的方法。我添加了一个性能测试来向您展示,对于更大的数据集,您将开始看到差异。如果您仍然认为嵌套循环是您的b,请告诉我
    arr1.reduce(function (acc, e) {
      for (let element of arr2) {
        /* ... */
      }
    })