Найти дубликаты объектов в массиве и вернуть новый массив объектов с количеством дубликатов в качестве нового свойства - PullRequest
1 голос
/ 07 ноября 2019

поэтому у меня есть массив объектов, который выглядит, например, следующим образом:

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

Я могу считать дубликаты объектов на основе одного параметра, но я не знаю, как это сделать на основе всего объекта. Каков наилучший способ решить эту проблему?

Ответы [ 5 ]

2 голосов
/ 07 ноября 2019

Я думаю, что вам лучше всего подойдет вспомогательный объект. Первоначально вспомогательный объект будет пустым, но он будет постепенно заполняться тем, что вы читаете. Я собираюсь предположить, что ключи в вашем массиве непротиворечивы.

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, потому что мы только что создали этот объект;его бы не было, если бы мы его не нашли.

Если объект уже существует, мы просто увеличиваем атрибут «times». В конце у нас есть объект, который выглядит следующим образом:

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])
}

Это вернет окончательное значение в указанном вами формате!

1 голос
/ 07 ноября 2019

Вы можете сделать это с помощью комбинации .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)
0 голосов
/ 09 ноября 2019

Просто выполните операцию сопоставления с вложенной операцией фильтрации, чтобы узнать, сколько раз появляются повторяющиеся объекты. Легко.

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);
0 голосов
/ 07 ноября 2019

Это можно сделать, используя 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));

ОБНОВЛЕНИЕ:

Если вы хотите найти дубликаты клавиш Name и Type, то вы можете сделать:

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));
0 голосов
/ 07 ноября 2019

Вы можете циклически перемещаться по массиву объектов, используя объект для хранения количества раз, когда появляется определенное «Имя». Затем выполните цикл по новому массиву объектов и назначьте ключ времени для объекта, на котором был установлен счетчик.

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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...