У меня есть 2 массива объектов в JavaScript, и я хотел бы сравнить и объединить содержимое и отсортировать результаты по идентификатору. В частности, результирующий отсортированный массив должен содержать все объекты из 1-го массива плюс все объекты из 2-го массива, которые имеют идентификатор, не входящий в 1-й.
Следующий код вроде работает (без сортировки). Но должен быть лучший и более лаконичный способ сделать это, особенно с функциями 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.info(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 [JS]](https://i.imgur.com/WsjO6zJb.png)


Одним из вариантов сложности O(N) было бы создание Set из id в cars1, затем распространение cars1 и отфильтрованного cars2 в выходной массив, с проверкой фильтра, включен ли id в автомобиле, который повторяется в cars2, в набор:
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.info(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.info(combined);Для этого идеально подходит объектный подход Set(). +1
Просто добавьте этот метод sort() в последнюю строку, например это, чтобы убедиться, что новый массив тоже отсортирован: combined.sort((a,b) => (a.id > b.id) ? 1 : ((b.id > a.id) ? -1 : 0));.
@CertainPerformance Это работает хорошо, но когда я удаленно удаляю элемент из БД, он должен быть удален из пользовательского интерфейса, но удаленный элемент застревает в пользовательском интерфейсе: \ НО, когда я добавляю новый элемент удаленно, он добавляется очень хорошо!
@OliverD Ни в этом вопросе, ни в моем ответе нет БД или удаленных подключений. Если у вас есть новый вопрос, нажмите кнопку «Задать вопрос».
Вы можете использовать concat, filter и 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}, ];
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.info(cars1);Вы можете использовать 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.info(merge(cars1, cars2));.as-console-wrapper { max-height: 100% !important; top: 0; }Объедините два массива, поместите каждый элемент массива на карту с их 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.info(final)Вы можете взять 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.info(result);Предполагая, что идентификатор должен быть уникальным, это должно работать:
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;
}
Но с вашими текущими примерами cars1 и cars2 вам может потребоваться объединение объектов. См. Сравнение объектов в JavaScript [дубликат]
Один из подходов может заключаться в использовании concat() с элементами cars2, чьи идентификаторы еще не находятся на 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.info(res);.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
Этот вопрос следует разместить в Обзор кода | StackExchange