javascript中的逻辑合并数组

javascript中的逻辑合并数组,javascript,arrays,Javascript,Arrays,我在mysql数据库中有一些单个实体的数据分布在多个表中。当我获取这些数据时,我得到的是包含同一逻辑实体的数据的独立数组。因此,我想在逻辑上合并这些单独的阵列,以便在我的应用程序上轻松使用。一个简单的例子是: 阵列: cakes = [ {id: 1, name: 'A'}, {id: 2, name: 'B'}, {id: 3, name: 'C'} ] flavours = [ {id:

我在mysql数据库中有一些单个实体的数据分布在多个表中。当我获取这些数据时,我得到的是包含同一逻辑实体的数据的独立数组。因此,我想在逻辑上合并这些单独的阵列,以便在我的应用程序上轻松使用。一个简单的例子是:

阵列:

cakes = [
          {id: 1, name: 'A'},
          {id: 2, name: 'B'},
          {id: 3, name: 'C'}
         ]

flavours = [
             {id: 1, cakeId: 2, flavour: 'mint'},
             {id: 2, cakeId: 2, flavour: 'strawberry'},
             {id: 3, cakeId: 3, flavour: 'mint'}
           ]
我们的目标是将这两个数组合并为一个数组,这与Flavors数组中对蛋糕数组(cakeId)的引用有关。在本例中,我期望的最后一个数组是:

newCakesArray = [
                 {id: 1, name: 'A'},
                 {id: 2, name: 'B', flavours: {id: 1, cakeId: 2, flavour: 'mint'},
                                              {id: 2, cakeId: 2, flavour: 'strawberry'}},
                 {id: 3, name: 'C', flavours: {id: 3, cakeId: 3, flavour: 'mint'}}
                ]
非常感谢您的帮助。

var-cakes=[
{id:1,名称:'A'},
{id:2,名称:'B'},
{id:3,名称:'C'}
];
变种风味=[
{id:1,cakeId:2,味道:'薄荷'},
{id:2,cakeId:2,味道:'草莓'},
{id:3,cakeId:3,味道:'mint'}
];
//让我们基于id字段创建一个索引表。
var cakesObs={};
用于(蛋糕中的蛋糕){
cakesObs[cake.id]=Object.assing({},cake);//克隆cake以避免更改原始对象
cakesObs[cake.id].flavors=[];//默认情况下为空数组。
}
//向索引表中添加风味
用于(不同风味){
cakesObs[flavor.cakeId].flavors.push(flavor);
}
//将桌子转换回一系列蛋糕,但现在有了味道。
var newCakesArray=Object.values(cakesObs);

您可以迭代蛋糕数组并添加“flavours”属性。要检查flavours数组中应该添加哪些对象,请使用“filter”函数

for (const i in cakes) {
  const cakeId = cakes[i].id;
  cakes[i].flavours = flavours.filter(f => f.cakeId === cakeId)
}

使用
reduce
迭代
cakes
数组。内部回调函数使用过滤器通过匹配
id
&
cakeId
flavors
获取对象。如果累加器对象具有与cake
id
相同的和键,则更新或创建
flavor
键。迭代后,使用
Object.values
获得最终数组

let cakes=[{
id:1,
姓名:“A”
},
{
id:2,
姓名:'B'
},
{
id:3,
姓名:“C”
}
]
让味道=[{
id:1,
卡基德:2,
味道:“薄荷”
},
{
id:2,
卡基德:2,
味道:“草莓”
},
{
id:3,
卡基德:3,
味道:“薄荷”
}
]
让newData=cakes.reduce((acc,curr)=>{
让getFlavours=flavours.filter(item=>item.cakeId===curr.id);
如果(!acc[当前id]){
acc[当前id]=当前;
}
如果(GetFlavors.length>0){
acc[curr.id].flavours=getFlavours
}
返回acc;
}, {})

console.log(Object.values(newData))
如果您不确定这两个数组中的顺序,可以执行以下操作:

cakes.map(cake => {
   const flavours = flavours.find(f => f.cakeId === cake.id);
   if(flavours) return {
     ...cake,
     flavours
   }
  return cake;
})
如果您担心空间复杂性,不想创建另一个阵列,可以就地创建

for(let i=0;i<cakes.length;i++) {
    const flavours = flavours.find(f => f.cakeId === cake.id);
    if(flavours) cakes[i].flavours = flavours;
}
for(设i=0;if.cakeId==cake.id);
if(风味)蛋糕[i].风味=风味;
}

为了减少与在flavors对象中搜索正确的cakeId相关的时间复杂性(搜索是在每次迭代中进行的,这非常昂贵),您应该按照cakeId对flavors进行排序,然后对cakeId进行二进制搜索。它将是
nlogn
复杂度,而不是
n**2

这项工作。这是否也适用于长度超过300k的非常大的阵列?这里的复杂性更高,因为对于每个
cake
,都有一个额外的周期
。filter
,这意味着对于N个cake,有1+N个周期(减少+所有过滤器)。在我的回答中,不管蛋糕的数量有多少,都有2个周期。我回答他的问题是因为300k周期的数量很重要。@satanTime浏览器在迭代300k元素时可能永远无法保证性能,除非使用service worker。这就是人们应该编写优化代码的原因。如果你知道你的访问者可能在一台速度很慢的笔记本电脑上-只需跳过30万个周期,只运行2次,就可以给他/她更好的用户体验。出于某种原因,插入的对象在控制台上以“cakes:[[object]、[object]、[object]]”的形式注销。我发现这种方法也很有效。它是否也适用于长度超过300k的超大阵列?这是否适用于长度超过300k的超大阵列?是的,它会。它使用
风格的指针
,问题只针对
蛋糕
,如果您不需要原始对象,可以对其进行变异,只需将
cakesObs[cake.id]=object.assing({},cake)
替换为
cakesObs[cake.id]=cake
。谢谢。谢谢你的答复。我赞成你的答案,但它不会显示出我在平台上的声誉是不足以考虑公众投票的。谢谢,最重要的是如果解决方案符合你的预期。这会对很大的数组长度起作用吗?大约300 K加上。如果你非常关心空间复杂度,我建议你把它放在适当的位置。我会更新我的答案