Получение объектов, содержащих одинаковый идентификатор в массиве объектов, в новый массив

#javascript #arrays #algorithm #duplicates

#javascript #массивы #алгоритм #дубликаты

Вопрос:

Я хочу получить все объекты с одинаковым идентификатором в новый массив. В приведенных ниже данных первый объект с id: 1 повторяется на 3-й и 5-й позиции, поэтому мне нужно сохранить объект 1-й, 3-й и 5-й позиции в новый массив. То же самое, если id в данных повторяется больше

Данные:

 const data = [
  { id: 1, file: 'test1.xlsx' },
  { id: 3, file: 'test1.xlsx' },
  { id: 1, file: 'test2.xlsx' },
  { id: 5, file: 'test2.xlsx' },
  { id: 1, file: 'test3.xlsx' },
  { id: 7, file: 'test3.xlsx' },
  { id: 8, file: 'test4.xlsx' },
  { id: 9, file: 'test4.xlsx' },
  { id: 9, file: 'test5.xlsx' },
  { id: 10, file: 'test5.xlsx' },
  { id: 9, file: 'test6.xlsx' },
]
 

Мой код:

 // arr = data
// headerKey = 'id'
const getDuplicates = (arr, headerKey) => {
  return arr
    .map((el, i) => {
      return arr.find((element, index) => {
        if (i !== index amp;amp; element[headerKey] === el[headerKey]) {
          return el
        }
      })
    })
    .filter((x) => x)
}
 

Мой неверный вывод

 [
  { id: 1, file: 'test2.xlsx' },
  { id: 1, file: 'test1.xlsx' },
  { id: 1, file: 'test1.xlsx' },
  { id: 9, file: 'test5.xlsx' },
  { id: 9, file: 'test4.xlsx' },
  { id: 9, file: 'test4.xlsx' }
]
 

ожидаемый результат

 [
  { id: 1, file: 'test1.xlsx' },
  { id: 1, file: 'test2.xlsx' },
  { id: 1, file: 'test3.xlsx' },
  { id: 9, file: 'test4.xlsx' },
  { id: 9, file: 'test5.xlsx' },
  { id: 9, file: 'test6.xlsx' }
]
 

В неправильном разделе вывода объект с { id: 1, file: 'test1.xlsx' } повторяется 2 раза, чего не должно быть, и то же самое с другой повторяющейся записью.

Я думаю, я смог понять, что моя текущая проблема и причина, по которой вывод неверен, возможно, потому find() , что метод возвращает только первый элемент.

Я искал решения в Интернете, и многие люди рекомендовали использовать метод reduce или filter, но я не могу понять, как его реализовать.

Ответ №1:

Мы можем добиться ожидаемого результата, используя Object.values Array.reduce и, наконец, проверяя длину накопленного массива, чтобы получить дублированные id файлы с соответствующими файлами, как показано ниже.

 const data = [{id:1,file:'test1.xlsx'},{id:3,file:'test1.xlsx'},{id:1,file:'test2.xlsx'},{id:5,file:'test2.xlsx'},{id:1,file:'test3.xlsx'},{id:7,file:'test3.xlsx'},{id:8,file:'test4.xlsx'},{id:9,file:'test4.xlsx'},{id:9,file:'test5.xlsx'},{id:10,file:'test5.xlsx'},{id:9,file:'test6.xlsx'}];

const findDuplicates = (data) => {
  const output = [];
  Object.values(data.reduce((res, obj) => {
    let key = obj.id;
    res[key] = [...(res[key] || []), {...obj}]
    return res;
  }, {})).forEach(arr => {
    if(arr.length > 1) {
      output.push(...arr);
    }
  });
  return output;
}

console.log(findDuplicates(data)); 
 .as-console-wrapper {
  max-height: 100% !important;
} 

Ответ №2:

Для меньшей вычислительной сложности, не .find внутри вашего .map — это O(n ^ 2) . Я бы подсчитал количество вхождений данного id объекта в объект (или карту), а затем, в конце, отфильтровал значения по коллекциям, в которых содержится не менее 2 значений:

 const data = [
  { id: 1, file: 'test1.xlsx' },
  { id: 3, file: 'test1.xlsx' },
  { id: 1, file: 'test2.xlsx' },
  { id: 5, file: 'test2.xlsx' },
  { id: 1, file: 'test3.xlsx' },
  { id: 7, file: 'test3.xlsx' },
  { id: 8, file: 'test4.xlsx' },
  { id: 9, file: 'test4.xlsx' },
  { id: 9, file: 'test5.xlsx' },
  { id: 10, file: 'test5.xlsx' },
  { id: 9, file: 'test6.xlsx' },
]

// arr = data
// headerKey = 'id'
const getDuplicates = (arr, headerKey) => {
  const objsByHeader = {};
  for (const obj of arr) {
    objsByHeader[obj[headerKey]] ??= [];
    objsByHeader[obj[headerKey]].push(obj);
  }
  return Object.values(objsByHeader)
    .filter(subarr => subarr.length >= 2)
    .flat();
}
console.log(getDuplicates(data, 'id')); 

Комментарии:

1. index.js:51 objsByHeader[obj[headerKey]] ??= [] ^ SyntaxError: неожиданный токен ‘=’ я получаю эту ошибку, я хотел бы указать, что я использую nodejs,

2. ??= это логическое присваивание с нулевым значением, которое совместимо с nodejs v15.0.0 и далее.

3. @PawanKanhere Если вы не можете использовать ??= , вы можете сделать if (!objsByHeader[obj[headerKey]]) objsByHeader[obj[headerKey]] = []