【问题标题】:Find duplicate objects in array and return new array of object with number of duplicates as a new property在数组中查找重复对象并返回具有重复数的新对象数组作为新属性
【发布时间】:2020-03-04 09:15:01
【问题描述】:

所以我有一个对象数组,例如:

let arrayOfObjects = [
  {
    Name: "Apple",
    Type: "Fruit"
  },
  {
    Name: "Carrot",
    Type: "Vegetable"
  },
  {
    Name: "Carrot",
    Type: "Vegetable"
  },
  {
    Name: "Carrot",
    Type: "Vegetable"
  },
  {
    Name: "Apple",
    Type: "Fruit"
  },
  {
    Name: "Apple",
    Type: "Fruit"
  },
  {
    Name: "Carrot",
    Type: "Vegetable"
  }
];

我需要仔细检查它,找到重复项并为每个重复项仅返回一个对象,但将重复项的数量作为新参数。

像这样:

let newArrayOfObjects = [
  {
    Name: "Apple",
    Type: "Fruit",
    times: 3,
  },
  {
    Name: "Carrot",
    Type: "Vegetable",
    times: 4,
  }
];

我可以根据一个参数计算重复对象,但我不知道如何根据整个对象来做。解决这个问题的最佳方法是什么?

【问题讨论】:

    标签: javascript arrays object filter


    【解决方案1】:

    我认为您最适​​合创建一个辅助对象。辅助对象最初是空的,但会根据您正在阅读的内容慢慢填充。我将假设您的数组中的键是一致的。

    const keys = ["Name","Type"]
    var counterObj = {}
    let keyForCounterObj
    arrayOfObjects.forEach((obj)=>{
        keyForCounterObj = ''
        keys.forEach((key)=>{
            keyForCounterObj += String(obj[key])
    }
    if(counterObj[keyForCounterObj]){
        counterObj[keyForCounterObj].times ++
    }else{
        counterObj[keyForCounterObj] = {
            ...obj,
            times:1
    }}}
    

    让我们把它分解一下,因为我知道如果您以前从未见过这种设置可能会有点混乱。

    我们循环遍历数组中的每个对象,并根据该对象存储的所有值构造一个键。例如,arrayOfObjects[0] 将创建“AppleFruit”键。 (我正在使用 String() 方法,以防万一这被应用于仅具有整数或浮点值的对象,因为在 javaScript 中创建键是无效的。对于您的特定问题,这不是必需的)

    一旦我们有了那个键,我们就会检查它是否存在于我们的 counterObject 中。如果它不存在,那么我们定义它。我们将“times”属性设置为1,因为我们刚刚创建了这个对象;除非我们刚刚找到它,否则它不会存在。

    如果对象已经存在,那么我们只需增加“次”属性。最后,我们有一个如下所示的对象:

    counterObj = {
        AppleFruit: {
            Name:"Apple",
            Type:"Fruit",
            times:3,
        },
        CarrotVegetable:{
            Name:"Carrot",
            Type:"Vegetable",
            times:4,
        }
    }
    

    好的,现在我们有了一个对象对象。让我们把它变成一个数组!

    let newArrayOfObjects = []
    const counterObjKeys = Object.keys(counterObj)
    counterObjKeys.forEach((key)=>{
        newArrayOfObjects.push(counterObj[key])
    }
    

    这将以您指定的格式返回最终值!

    【讨论】:

    • 这似乎是正确且有效的解决方案。谢谢。
    • 很高兴为您提供帮助。如果有什么不清楚或挥手,请告诉我。如果需要,我很乐意详细说明。
    【解决方案2】:

    您可以循环访问对象数组,同时使用一个对象来保存某个“名称”出现的次数。然后循环遍历新的对象数组并从持有计数器的对象中分配时间键。

    let arrayOfObjects = [
      {Name: "Apple", Type: "Fruit"},
      {Name: "Carrot", Type: "Vegetable"},
      {Name: "Carrot", Type: "Vegetable"},
      {Name: "Carrot", Type: "Vegetable"},
      {Name: "Apple", Type: "Fruit"},
      {Name: "Apple", Type: "Fruit"},
      {Name: "Carrot", Type: "Vegetable"}
    ];
    let newArrayOfObjects = [];
    // object that holds how many times a "Name" value appears.
    var uniqueNames = {};
    // loop through array of objects
    for (var i = 0; i < arrayOfObjects.length; i++) {
      // if uniqueNames key does not exist
      if (!uniqueNames[arrayOfObjects[i].Name]) {
        // push this object into new array
        newArrayOfObjects.push(arrayOfObjects[i]);
      }
      // use this as a counter for each "Name" value
      uniqueNames[arrayOfObjects[i].Name] = ((uniqueNames[arrayOfObjects[i].Name] || 0) + 1);
    }
    // loop through new array of objects, and add the "times" key to it
    for (var j = 0; j < newArrayOfObjects.length; j++) {
      newArrayOfObjects[j].times = uniqueNames[newArrayOfObjects[j].Name];
    }
    console.log(newArrayOfObjects);
    

    【讨论】:

    • 我知道这种可能的解决方案,但它是不需要的,因为它会返回 { Name: 'Carrot', Type: 'Vegetable', times: 4 },即使其中一个对象是这样的:{Name: "Carrot", Type: "Fruit"}。我需要完全匹配对象,而不仅仅是匹配它们的名称。
    【解决方案3】:

    您可以在原始数组上使用.map 的组合并使用.find 搜索新形成的数组的项目。

        let arrayOfObjects = [
        {
          Name: "Apple",
          Type: "Fruit"
        },
        {
          Name: "Carrot",
          Type: "Vegetable"
        },
        {
          Name: "Carrot",
          Type: "Vegetable"
        },
        {
          Name: "Carrot",
          Type: "Vegetable"
        },
        {
          Name: "Apple",
          Type: "Fruit"
        },
        {
          Name: "Apple",
          Type: "Fruit"
        },
        {
          Name: "Carrot",
          Type: "Vegetable"
        }
      ];
    
    const resultArray = [];
    
    arrayOfObjects.map(item => {
        //for each item in arrayOfObjects check if the object exists in the resulting array
        if(resultArray.find(object => {
            if(object.Name === item.Name && object.Type === item.Type) {
                //if the object exists iterate times
                object.times++;
                return true;
                //if it does not return false
            } else {
                return false;
            }
        })){
        } else {
            //if the object does not exists push it to the resulting array and set the times count to 1
            item.times = 1;
            resultArray.push(item);
        }
    })
    
    console.log(resultArray)

    更新:

    最好使用.reduce而不是.map,因为后者主要用于对数组的每个元素应用某个函数,并得到一个函数执行结果数组。

    另一方面,Array .reduce() 方法也在每个项目上执行一个函数(回调),但它将结果从一个元素数组传递到另一个元素数组。因此,我们可以使用一个空数组作为开始,然后用一个对象填充它,或者迭代.times 属性,以防当前元素存在于传递给每个回调的累积数组中。

    这是一个例子:

    let arrayOfObjects = [
      {
        Name: "Apple",
        Type: "Fruit"
      },
      {
        Name: "Carrot",
        Type: "Vegetable"
      },
      {
        Name: "Carrot",
        Type: "Vegetable"
      },
      {
        Name: "Carrot",
        Type: "Vegetable"
      },
      {
        Name: "Apple",
        Type: "Fruit"
      },
      {
        Name: "Apple",
        Type: "Fruit"
      },
      {
        Name: "Carrot",
        Type: "Vegetable"
      }
    ];
    
    
    const newArrayOfObjects = 
      arrayOfObjects.reduce((accumulator, object) => {
        if(objectFound = accumulator.find(arrItem => arrItem.Name === object.Name && arrItem.Type === object.Type)) {
            objectFound.times++;
        } else {
            object.times = 1;
            accumulator.push(object);
        }
        return accumulator;
      }, []);
    
    console.log(newArrayOfObjects);

    【讨论】:

      【解决方案4】:

      可以使用reduce方法完成:

      const arrayOfObjects = [
        {
          Name: "Apple", Type: "Fruit"
        },
        {
          Name: "Carrot", Type: "Vegetable"
        },
        {
          Name: "Carrot", Type: "Vegetable"
        },
        {
          Name: "Carrot", Type: "Vegetable"
        },
        {
          Name: "Apple",  Type: "Fruit"
        },
        {
          Name: "Apple",  Type: "Fruit"
        },
        {
          Name: "Carrot", Type: "Vegetable"
        }
      ];
      
      
      const result = arrayOfObjects.reduce((a, {Name, Type}) => {
        a[Name] = a[Name] || {Name, Type, times: 0};
        a[Name].times += 1;
        return a;
      }, {})
      
      console.log(Object.values(result));

      更新:

      如果你想找到与NameType 重复的键,那么你可以这样做:

      const arrayOfObjects = [
        {
          Name: "Apple", Type: "Super Meal"
        },
        {
          Name: "Carrot", Type: "Vegetable"
        },
        {
          Name: "Carrot", Type: "Vegetable"
        },
        {
          Name: "Carrot", Type: "Vegetable"
        },
        {
          Name: "Apple",  Type: "Fruit"
        },
        {
          Name: "Apple",  Type: "Fruit"
        },
        {
          Name: "Carrot", Type: "Vegetable"
        }
      ];
      
      const result = [...arrayOfObjects.reduce((r, o) => {
      
        const key = o.Name + '-' + o.Type;
      
        const item = r.get(key) || Object.assign({}, o, {
      times: 0
        });
      
        item.times += 1;
      
        return r.set(key, item);
      }, new Map).values()];
      
      console.log(Object.values(result));

      【讨论】:

      • 同样,这不是一个受欢迎的解决方案,因为它仅根据名称比较对象。
      • @Esszed 你想通过NameType 进行比较吗?抱歉,您能说明一下要求是什么吗?
      • 问题中说。我需要找到重复的对象而不仅仅是一个重复的参数。重复对象意味着所有参数都相同。
      【解决方案5】:

      只需使用嵌套过滤器操作进行映射操作即可获取重复对象出现的次数。简单。

      let arrayOfObjects = [{
          Name: "Apple",
          Type: "Fruit"
      }, {
          Name: "Carrot",
          Type: "Vegetable"
      }, {
          Name: "Carrot",
          Type: "Vegetable"
      }, {
          Name: "Carrot",
          Type: "Vegetable"
      }, {
          Name: "Apple",
          Type: "Fruit"
      }, {
          Name: "Apple",
          Type: "Fruit"
      }, {
          Name: "Carrot",
          Type: "Vegetable"
      }];
      var returnedArray = [];
      
      function countNumberIn(obj, array) {
          return array.filter(function(object) {
              return ((object.Name == obj.Name) && (object.Type == obj.Type))
          }).length;
      }
      arrayOfObjects.map(function(obj) {
          obj.count = countNumberIn(obj, arrayOfObjects);
          return obj;
      }).forEach(function(obj) {
          if (countNumberIn(obj, returnedArray) == 0) {
              returnedArray.push(obj);
          }
      });
      console.log(returnedArray);

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-03-13
        • 2017-02-02
        • 1970-01-01
        • 2019-06-28
        • 1970-01-01
        • 2018-08-13
        • 1970-01-01
        • 2015-12-14
        相关资源
        最近更新 更多