Javascript 如何可靠地合并这两个数组中的对象,并以苗条的方式循环生成的数组?
我有2个对象数组,每个对象都包含我希望合并的信息。这些数组有一个公共密钥:Javascript 如何可靠地合并这两个数组中的对象,并以苗条的方式循环生成的数组?,javascript,svelte,Javascript,Svelte,我有2个对象数组,每个对象都包含我希望合并的信息。这些数组有一个公共密钥: let countries = [ { code: "AF", name: "Afghanistan" }, { code: "AL", name: "Albania" }, { code: "IL", name: "Israel" }, ] let dial = [
let countries = [
{ code: "AF", name: "Afghanistan" },
{ code: "AL", name: "Albania" },
{ code: "IL", name: "Israel" },
]
let dial = [
{ code: "AF", dial_code: "+93" },
{ code: "AL", dial_code: "+355" },
{ code: "IL", dial_code: "+972" },
]
我通过以下方式将上述阵列合并为一个新阵列:
let merged = countries.map((item, i) => Object.assign({}, item, dial[i]));
然后,我使用Svelte在表格中显示信息:
<table class="table table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Code</th>
<th>Dial Code</th>
</tr>
</thead>
<tbody>
{#if countries.length}
{#each merged as m}
<tr>
<td>{m.name}</td>
<td>{m.code}</td>
<td>{m.dial_code}</td>
</tr>
{/each}
{:else}
<tr>
<td colspan="3">There are no countries</td>
</tr>
{/if}
</tbody>
</table>
一种方法是使用
reduce
,将两个数组合并到一个数组中,然后获取它的Object.value。以下是一个例子:
var-dial=[{code:“IL”,dial_代码:“+972”},{code:“AF”,dial_代码:“+93”},{code:“AL”,dial_代码:“+355”},];
var国家=[{代码:“AF”,名称:“阿富汗”},{代码:“AL”,名称:“阿尔巴尼亚”},{代码:“IL”,名称:“以色列”}];
var结果=对象。值([…拨号,…国家])。减少((acc,elem)=>{
acc[elem.code]={…(acc[elem.code]|{}),…elem};
返回acc;
},{}));
控制台日志(结果)代码>这里是不同的方法
let countries=[
{代号:“AF”,名称:“阿富汗”},
{代号:“AL”,名称:“阿尔巴尼亚”},
{代码:“IL”,名称:“以色列”},
]
让我们拨号=[
{代码:“AF”,拨号代码:“+93”},
{代码:“AL”,拨号代码:“+355”},
{代码:“IL”,拨号代码:+972},
{代码:“ILi”,拨号代码:+972}
]
结果=[]
每小时拨号((x)=>{
countries.forEach(o=>{
如果(x.code==o.code)
返回result.push(Object.assign({},o,x))
})
})
console.log(result)
这里的一些答案基本上使用嵌套循环(在forEach
中使用forEach
,或者在映射中使用find
)。在这种情况下,这可能很好,但是这种方法的性能是O(n^2),这是一个危险信号。如果有第三个数据数组要用类似的方法合并,它将变成O(n^3),依此类推
更具可扩展性的解决方案是使用查找:
const sources=[国家/地区,拨号];//加上任何你在未来添加!
const codes=new Set(//使用Set是一种简单的重复数据消除方法
sources.map(source=>source.map(d=>d.code)).flat()
);
const lookups=sources.map(source=>{
const lookup=新映射();
forEach(d=>lookup.set(d.code,d));
返回查找;
});
const combined=Array.from(代码,代码=>{
返回Object.assign({},…lookups.map(d=>d.get(code)|{}));
});
我认为排序比内置数据结构更有效
let countries = [
{ code: "AF", name: "Afghanistan" },
{ code: "AL", name: "Albania" },
{ code: "IL", name: "Israel" },
]
let dial = [
{ code: "AF", dial_code: "+93" },
{ code: "AL", dial_code: "+355" },
{ code: "IL", dial_code: "+972" },
]
const combine = (arr1, arr2) => {
const combined = arr1.concat(arr2)
combined.sort((x, y) => x.code.localeCompare(y.code))
const result = [combined[0]]
for (let i = 1; i < combined.length; i++) {
if (combined[i].code == combined[i - 1].code) {
result[result.length - 1] = { ...result[result.length - 1], ...combined[i] }
} else {
result.push(combined[i])
}
}
return result
}
console.log(combine(countries, dial))
let countries=[
{代号:“AF”,名称:“阿富汗”},
{代号:“AL”,名称:“阿尔巴尼亚”},
{代码:“IL”,名称:“以色列”},
]
让我们拨号=[
{代码:“AF”,拨号代码:“+93”},
{代码:“AL”,拨号代码:“+355”},
{代码:“IL”,拨号代码:+972},
]
const combine=(arr1,arr2)=>{
const combled=arr1.concat(arr2)
组合.sort((x,y)=>x.code.localeCompare(y.code))
常量结果=[组合[0]]
for(设i=1;i
哪种方法在两个数组长度不相等的情况下仍然有效?在这种情况下,哪种数组是新长度的定义数组?@RazvanZamfir两者都有效。在reduce
的情况下,如果拨号代码不存在,则不会在对象中插入密钥,如果使用second,则密钥将存在,但具有未定义的值。你最好用一些虚拟数据在你的计算机上测试它。选择一个,非常漂亮的解决方案。但是,我已经对您的解决方案与嵌套的foreach进行了性能测试,至少在这种情况下,该解决方案比嵌套的foreach慢,而且在数组长度不相同的情况下,它似乎会添加不需要的数据,但是,尽管这种方法可以很容易地修改,以使用出现在两个源或其中一个源中的所有代码集,但这可能是可以避免的。重新表演:是的,很明显,当你有三个项目时,设置最少的技术将获胜。但这不是一件值得优化的事情。这里的方法是O(n),而在最佳情况下,forEach
方法是O(n^2)。所讨论的数据是一个国家列表,其中约有200个国家——有了这些数据量,O(n)算法的速度已经是naiveforEach
方法的几倍。用(比如)10000个项目,O(n ^ 2)是灾难性的慢。谢谢你的评论,我同意这个解决方案是可扩展的,它对于大数据肯定更快,但是你不认为你的解决方案中的最后一行是嵌套循环吗?因为您正在使用Array.from
遍历键,并且在键内使用map
遍历map
,它们都会复制数组,因为Array.from内部机制也使用map
?是否可以避免嵌套Array.from和map?@Sven.hig,区别在于…lookups.map(…)
在2次查找上循环,而不是在n行数据上循环。这就是为什么这是O(n)而不是O(n^2)。另外,我非常怀疑Array.from
是否在内部使用map
;没有理由这样做如果我希望结果
数组只包含名称
和拨号代码
属性,该怎么做?
let countries = [
{ code: "AF", name: "Afghanistan" },
{ code: "AL", name: "Albania" },
{ code: "IL", name: "Israel" },
]
let dial = [
{ code: "AF", dial_code: "+93" },
{ code: "AL", dial_code: "+355" },
{ code: "IL", dial_code: "+972" },
]
const combine = (arr1, arr2) => {
const combined = arr1.concat(arr2)
combined.sort((x, y) => x.code.localeCompare(y.code))
const result = [combined[0]]
for (let i = 1; i < combined.length; i++) {
if (combined[i].code == combined[i - 1].code) {
result[result.length - 1] = { ...result[result.length - 1], ...combined[i] }
} else {
result.push(combined[i])
}
}
return result
}
console.log(combine(countries, dial))