【问题标题】:Compare 2 Arrays of Objects and Remove Duplicates比较 2 个对象数组并删除重复项
【发布时间】:2019-01-11 07:31:08
【问题描述】:

我在 JavaScript 中有 2 个对象数组,想比较和合并内容并按 id 对结果进行排序。具体来说,生成的排序数组应包含第一个数组中的所有对象,以及第二个数组中所有 id 不在第一个数组中的对象。

以下代码似乎有效(减去排序)。但是必须有更好、更简洁的方法来做到这一点,尤其是使用 ES6 的特性。我认为使用 Set 是可行的方法,但不确定如何实现。

    var cars1 = [
        {id: 2, make: "Honda", model: "Civic", year: 2001},
        {id: 1, make: "Ford",  model: "F150",  year: 2002},
        {id: 3, make: "Chevy", model: "Tahoe", year: 2003},
    ];
    
    var cars2 = [
        {id: 3, make: "Kia",    model: "Optima",  year: 2001},
        {id: 4, make: "Nissan", model: "Sentra",  year: 1982},
        {id: 2, make: "Toyota", model: "Corolla", year: 1980},
    ];
    
    // Resulting cars1 contains all cars from cars1 plus unique cars from cars2
    cars1 = removeDuplicates(cars2);
    console.log(cars1);
    
    function removeDuplicates(cars2){
        for (entry in cars2) {
            var keep = true;
    
            for (c in cars1) {
                if (cars1[c].id === cars2[entry].id) {
                    keep = false;
                }
            }
    
            if (keep) {
                cars1.push({
                    id:cars2[entry].id,
                    make:cars2[entry].make,
                    model:cars2[entry].model,
                    year:cars2[entry].year
                })
            }
        }
        return cars1;
    }

【问题讨论】:

标签: javascript arrays ecmascript-6


【解决方案1】:

具有O(N) 复杂性的一个选项是在cars1 中创建idSet,然后将cars1 和过滤后的cars2 传播到输出数组中,过滤器测试是否在 cars2 中迭代的汽车中的 id 包含在 Set 中:

var cars1 = [
    {id: 2, make: "Honda", model: "Civic", year: 2001},
    {id: 1, make: "Ford",  model: "F150",  year: 2002},
    {id: 3, make: "Chevy", model: "Tahoe", year: 2003},
];

var cars2 = [
    {id: 3, make: "Kia",    model: "Optima",  year: 2001},
    {id: 4, make: "Nissan", model: "Sentra",  year: 1982},
    {id: 2, make: "Toyota", model: "Corolla", year: 1980},
];
const cars1IDs = new Set(cars1.map(({ id }) => id));
const combined = [
  ...cars1,
  ...cars2.filter(({ id }) => !cars1IDs.has(id))
];
console.log(combined);

也给sort

combined.sort(({ id: aId }, {id: bId }) => aId - bId);

var cars1 = [
    {id: 2, make: "Honda", model: "Civic", year: 2001},
    {id: 1, make: "Ford",  model: "F150",  year: 2002},
    {id: 3, make: "Chevy", model: "Tahoe", year: 2003},
];

var cars2 = [
    {id: 3, make: "Kia",    model: "Optima",  year: 2001},
    {id: 4, make: "Nissan", model: "Sentra",  year: 1982},
    {id: 2, make: "Toyota", model: "Corolla", year: 1980},
];
const cars1IDs = new Set(cars1.map(({ id }) => id));
const combined = [
  ...cars1,
  ...cars2.filter(({ id }) => !cars1IDs.has(id))
];
combined.sort(({ id: aId }, {id: bId }) => aId - bId);
console.log(combined);

【讨论】:

  • Set() 对象方法非常适合这一点。 +1
  • 只需在最后一行添加这个sort() 方法,如this 以确保新数组也已排序:combined.sort((a,b) => (a.id > b.id) ? 1 : ((b.id > a.id) ? -1 : 0));
  • @CertainPerformance 它运行良好,但是当我从数据库远程删除一个项目时,它应该从 UI 中删除,但已删除的项目卡在 UI 中:\ 但是当我远程添加新项目时,它添加得很好!
  • @OliverD 这个问题和我的回答都没有数据库或远程连接。如果您有新问题,请按按钮
【解决方案2】:

您可以使用concatfiltermap

var cars1 = [ {id: 2, make: "Honda", model: "Civic", year: 2001}, {id: 1, make: "Ford", model: "F150", year: 2002}, {id: 3, make: "Chevy", model: "Tahoe", year: 2003}, ];

var cars2 = [ {id: 3, make: "Kia", model: "Optima", year: 2001}, {id: 4, make: "Nissan", model: "Sentra", year: 1982}, {id: 2, make: "Toyota", model: "Corolla", year: 1980}, ];

// Resulting cars1 contains all cars from cars1 plus unique cars from cars2
let ids = cars1.map(c => c.id);
cars1 = cars1.concat(cars2.filter(({id}) => !ids.includes(id)))
console.log(cars1);

【讨论】:

    【解决方案3】:

    合并两个数组,将每个数组元素与其ids 放在一个映射中,然后从映射值创建数组。

    var cars1 = [
        {id: 2, make: "Honda", model: "Civic", year: 2001},
        {id: 1, make: "Ford",  model: "F150",  year: 2002},
        {id: 3, make: "Chevy", model: "Tahoe", year: 2003},
    ];
    
    var cars2 = [
        {id: 3, make: "Kia",    model: "Optima",  year: 2001},
        {id: 4, make: "Nissan", model: "Sentra",  year: 1982},
        {id: 2, make: "Toyota", model: "Corolla", year: 1980},
    ];
    
    cars = cars1.concat(cars2);
    let foo = new Map();
    for(const c of cars){
      foo.set(c.id, c);
    }
    let final = [...foo.values()]
    console.log(final)

    【讨论】:

      【解决方案4】:

      您可以使用Map 并先获取其中的项目地图或实际汽车。

      var cars1 = [{ id: 2, make: "Honda", model: "Civic", year: 2001 }, { id: 1, make: "Ford",  model: "F150",  year: 2002 }, { id: 3, make: "Chevy", model: "Tahoe", year: 2003 }],
          cars2 = [{ id: 3, make: "Kia",    model: "Optima",  year: 2001 }, { id: 4, make: "Nissan", model: "Sentra",  year: 1982 }, { id: 2, make: "Toyota", model: "Corolla", year: 1980 }],
          result = Array
              .from(
                  [...cars1, ...cars2]
                      .reduce((m, c) => m.set(c.id, m.get(c.id) || c), new Map)
                      .values()
              )
              .sort((a, b) => a.id - b.id);
      
      console.log(result);

      【讨论】:

        【解决方案5】:

        您可以将Object.values().concat().reduce() 一起使用:

        let cars1 = [
            {id: 2, make: "Honda", model: "Civic", year: 2001},
            {id: 1, make: "Ford",  model: "F150",  year: 2002},
            {id: 3, make: "Chevy", model: "Tahoe", year: 2003},
        ];
        
        let cars2 = [
            {id: 3, make: "Kia",    model: "Optima",  year: 2001},
            {id: 4, make: "Nissan", model: "Sentra",  year: 1982},
            {id: 2, make: "Toyota", model: "Corolla", year: 1980},
        ];
        
        let merge = (arr1, arr2) => Object.values(
            arr1.concat(arr2).reduce((r, c) => (r[c.id] = r[c.id] || c, r), {})
        ).sort((a, b) => a.id - b.id);
        
        console.log(merge(cars1, cars2));
        .as-console-wrapper { max-height: 100% !important; top: 0; }

        【讨论】:

          【解决方案6】:

          假设 id 应该是唯一的,这应该可以工作:

          var union = (arr1, arr2) => 
          {
              var result = arr1.slice(0);
              arr2.forEach((el) => 
              { 
                  if (getIndexByAttribute(arr1, 'id', el.id) < 0)
                      result .push(el); 
              });
              return result;
          };
          
          var getIndexByAttribute = (array, attr, value) => {
              for(var i = 0; i < array.length; i += 1) {
                  if(array[i][attr] === value) {
                      return i;
                  }
              }
              return -1;
          }
          

          但是对于您当前的示例cars1cars2,您可能需要对象camparison。请看Object comparison in JavaScript [duplicate]

          【讨论】:

            【解决方案7】:

            一种方法可以将concat()cars2 的元素一起使用,其ID 尚未在cars1 上,这可以使用find() 进行检查。最后是sort() 得到的数组:

            var cars1 = [
                {id: 2, make: "Honda", model: "Civic", year: 2001},
                {id: 1, make: "Ford",  model: "F150",  year: 2002},
                {id: 3, make: "Chevy", model: "Tahoe", year: 2003},
            ];
                
            var cars2 = [
                {id: 3, make: "Kia",    model: "Optima",  year: 2001},
                {id: 4, make: "Nissan", model: "Sentra",  year: 1982},
                {id: 2, make: "Toyota", model: "Corolla", year: 1980},
            ];
            
            let res = cars1
                .concat(cars2.filter(({id}) => !cars1.find(x => x.id === id)))
                .sort((a, b) => a.id - b.id);
            
            console.log(res);
            .as-console {background-color:black !important; color:lime;}
            .as-console-wrapper {max-height:100% !important; top:0;}

            【讨论】:

              猜你喜欢
              • 2017-12-31
              • 2020-12-14
              • 1970-01-01
              • 2023-03-15
              • 2020-10-16
              • 2021-05-09
              • 2013-02-02
              • 2021-02-01
              • 2020-05-08
              相关资源
              最近更新 更多