#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.
??=
это логическое присваивание с нулевым значением, которое совместимо с nodejsv15.0.0
и далее.3. @PawanKanhere Если вы не можете использовать
??=
, вы можете сделатьif (!objsByHeader[obj[headerKey]]) objsByHeader[obj[headerKey]] = []