在 Svelte 中,如何可靠地合并这两个数组中的对象并循环生成的数组?

How can I reliably merge objects from these 2 arrays and loop the resulting array, in Svelte?

我有 2 个对象数组,每个对象都包含我希望合并的信息。数组有一个公共键:

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" },
]

我把上面的数组合并成一个 new 这样的:

let merged = countries.map((item, i) => Object.assign({}, item, dial[i]));

然后我使用 Svelte 在 table 中显示信息:

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

该方法的工作原理可以看出 here,但不是“防弹”:如果对象的顺序不同,则按 code 键,方法 returns bad/false 个结果。

即使 dial 数组如下所示,哪种方法也有效?

let dial = [
    { code: "IL", dial_code: "+972" },
    { code: "AF", dial_code: "+93" },
    { code: "AL",  dial_code: "+355" },
]

一种方法是使用 reduce,将两个数组合并为一个数组,然后从中获取 Object.values。这是一个例子:

var dial = [  { code: "IL", dial_code: "+972" }, { code: "AF", dial_code: "+93" }, { code: "AL",  dial_code: "+355" },];

var countries = [ { code: "AF", name: "Afghanistan" }, { code: "AL", name: "Albania" },{ code: "IL", name: "Israel" }];

var result = Object.values([...dial, ...countries].reduce((acc, elem)=>{
    acc[elem.code] = {...(acc[elem.code] || {}), ...elem};
    return acc;
},{}));

console.log(result);

或者您也可以使用 mapfind:

var dial = [  { code: "IL", dial_code: "+972" }, { code: "AF", dial_code: "+93" }, { code: "AL",  dial_code: "+355" },];

var countries = [ { code: "AF", name: "Afghanistan" }, { code: "AL", name: "Albania" },{ code: "IL", name: "Israel" }];

var result= countries.map(country=>({...country, dialo_code:dial.find(p=>p.code==country.code)?.dial_code}));

console.log(result);

这是不同的方法

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" },
  { code: "ILi", dial_code: "+972" }
]


result=[]
dial.forEach((x)=>{
    countries.forEach(o=>{
    if(x.code==o.code)
      return result.push(Object.assign({},o,x))
  })
 })
  
    
console.log(result)

这里的一些答案本质上是使用嵌套循环(forEach 内的 forEach,或 map 内的 find。在这种情况下这可能没问题,但这种方法的性能是 O(n^2),这是一个危险信号。如果你有一个 third 数据数组,你想用类似的方法合并,它将变成 O(n^3),依此类推。

一个更具扩展性的解决方案是使用查找:

const sources = [countries, dial]; // plus anything you add in future!

const codes = new Set( // using a set is an easy way to dedupe
  sources.map(source => source.map(d => d.code)).flat()
);

const lookups = sources.map(source => {
  const lookup = new Map();
  source.forEach(d => lookup.set(d.code, d));
  return lookup;
});

const combined = Array.from(codes, code => {
  return 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))