#javascript
#javascript
Вопрос:
Учитывая:
- массив «текущих» объектов
[{id: '1'},{id: '2'},{id: '3'},{id: '4'},{id: '5'}]
- массив «новых» объектов
[{id: '1'},{id: '5'},{id: '6'},{id: '7'},{id: '8'}]
Как определить, какие объекты
- для добавления (не в «текущем») и
- удалить (не в «новом»)?
В этом случае:
{id: '2'},{id: '3'},{id: '4'}
должен быть удален{id: '6'},{id: '7'},{id: '8'}
должен быть добавлен
Производительность не очень важна, мой набор данных обычно составляет около 200.
Редактировать: мне нужно знать об элементах, которые нужно добавлять / удалять, потому что «текущий» массив соотносится с узлами DOM, и я не просто хочу удалить их все и добавить с нуля — уже пробовал это, и производительность далека от совершенства.
Комментарии:
1. Что вы уже пробовали?
2. Почему бы просто не заменить «текущий» массив на «новый» массив, подобный
currentArray = newArray;
?3. @ibrahimmahrir «текущий» массив соотносится с DOM-узлами, я должен удалить старые DOM-узлы, и для этого мне нужно знать, какие из них. Да, я виноват, что забыл этот важный факт.
4. @Solo вы должны показать нам, что именно вы хотите сделать, и реальные данные, с которыми вы работаете, а не приводить пример с фиктивными объектами. Я предполагаю, что вы хотите, чтобы объекты были удалены как из DOM, так и из массива, но с примерами в вашем вопросе любое решение будет просто повторением замены «текущего» массива на «новый» массив.
5. @ibrahimmahrir Мой код все еще работает с объектами в массивах, выполнение мутаций DOM — это просто побочный эффект, поэтому я думаю, что это был бы бессмысленный и сбивающий с толку дополнительный код.
Ответ №1:
В обоих случаях это классический вариант использования операции set «разница». Все, что вам нужно сделать, это определить функцию разности, а затем применить ее с помощью current.difference(new)
и new.difference(current)
.
function difference(a, b, compare) {
let diff = [];
for (let ai = 0; ai < a.length; ai ) {
let exists = false;
for (let bi = 0; bi < b.length; bi ) {
if (compare(a[ai], b[bi])) {
exists = true;
break;
}
}
if (!exists) diff.push(a[ai]);
}
return diff;
}
function getRemoved(oldA, newA) {
return difference(oldA, newA, (a, b) => a.id == b.id);
}
function getAdded(oldA, newA) {
return difference(newA, oldA, (a, b) => a.id == b.id);
}
let current = [{id: '1'}, {id: '2'}, {id: '3'}, {id: '4'}, {id: '5'}];
let newArr = [{id: '1'}, {id: '5'}, {id: '6'}, {id: '7'}, {id: '8'}];
console.log(getRemoved(current, newArr));
console.log(getAdded(current, newArr));
Ответ №2:
- Для каждого элемента в current, который не найден в new. Этот элемент удаляется.
- Для каждого элемента в new, которого нет в current. Этот элемент добавлен.
Вы выполняете эти проверки в двух разных циклах один за другим.
Комментарии:
1. Так просто, но в то же время так эффективно. Я подумал, может быть, есть способ без создания новых «вспомогательных» массивов отслеживать вещи (чтобы избежать мусора), но я думаю, я мог бы их повторно использовать.
2. Вам не нужны вспомогательные массивы. Вы буквально запускаете набор проверок 2N ^ 2 временной сложности. Есть абсолютно разные способы сделать это лучше, особенно если элементы отсортированы так, как они выглядят. Но данных так мало, что лучше быть простым. Особенно потому, что, когда вы обычно выполняете эти операции, вам обычно требуется выполнить некоторую обработку каждого элемента. Например, объявляет некоторым системам, что эта вещь добавлена, а эта — что они удалены. Именно по этой причине вы сделали бы это вместо того, чтобы просто использовать новый список напрямую.
Ответ №3:
Вы могли бы использовать что-то вроде этого :
const currentElements = [{id: '1'},{id: '2'},{id: '3'},{id: '4'},{id: '5'}]
const newElements = [{id: '1'},{id: '5'},{id: '6'},{id: '7'},{id: '8'}]
const elementsToAdd = newElements.filter(e1 => !currentElements.find(e2 => e2.id === e1.id))
const elementsToRemove = currentElements.filter(e1 => !newElements.find(e2 => e2.id === e1.id))
console.log({elementsToAdd, elementsToRemove})
В принципе, я беру массив и нахожу элементы, не содержащиеся в другом массиве.
Для элементов, которые нужно добавить, проверьте элементы в newElements, которых нет в currentElements, и наоборот.
Комментарии:
1. Массив #some или Array#every лучше подходят для этой работы, чем
Array#find
Ответ №4:
Вы могли бы использовать Set
структуру данных для вычисления различных и фильтрации ожидаемых значений (используя ее has
метод). Временная сложность для этого подхода будет линейной ( O(n)
)
Set
используйте хэш-таблицу, чтобы сложность повторного запроса / поиска была O(1)
(документ, теория> Скорость поиска)
const prev = [{ id: "1" }, { id: "2" }, { id: "3" }, { id: "4" }, { id: "5" }] // length n
const current = [
{ id: "1" },
{ id: "5" },
{ id: "6" },
{ id: "7" },
{ id: "8" },
] // length m
const prevIdSet = new Set(prev.map((o) => o.id)) // O(n)
const currentIdSet = new Set(current.map((o) => o.id)) // O(m)
function difference(setA, setB) {
let _difference = new Set(setA)
for (let elem of setB) {
_difference.delete(elem)
}
return _difference
}
const removedIdSet = difference(prevIdSet, currentIdSet) // O(m)
const addedIdSet = difference(currentIdSet, prevIdSet) // O(n)
const removed = prev.filter((o) => removedIdSet.has(o.id)) // O(n)
const added = current.filter((o) => addedIdSet.has(o.id)) // O(m)
console.log("removed", removed)
console.log("added", added)
// Total complexity O(constantA * n constantB * m) ~ O(n m)
Ответ №5:
Вы могли бы использовать filter. Что-то вроде этого для элементов для удаления:
arr1.filter(function(i) {return arr2.indexOf(i) < 0;});
И поменяйте местами массивы для элементов для добавления. Например:
let arr1 = [{id: '1'},{id: '2'},{id: '3'},{id: '4'},{id: '5'}];
let arr2 = [{id: '1'},{id: '5'},{id: '6'},{id: '7'},{id: '8'}];
arr1 = arr1.map((obj) => obj.id);
arr2 = arr2.map((obj) => obj.id);
console.log("Remove these IDs: ", arr1.filter(function(i) {return arr2.indexOf(i) < 0;}));
console.log("Add these IDs: ", arr2.filter(function(i) {return arr1.indexOf(i) < 0;}));
Ответ №6:
Вам нужны только идентификаторы: вы могли бы извлечь идентификаторы с помощью flatMap
и чем filter
с every
вместо incudes
.
let old = [{id: '1'},{id: '2'},{id: '3'},{id: '4'},{id: '5'}];
let act = [{id: '1'},{id: '5'},{id: '6'},{id: '7'},{id: '8'}];
let oldIds = old.flatMap(el => el.id);
let actIds = act.flatMap(el => el.id);
let add = actIds.filter(id => oldIds.every(old=> !old.includes(id)));
let del = oldIds.filter(id => actIds.every(act=> !act.includes(id)));
console.log('Add: ', add);
console.log('Del: ', del);