Создайте Set из второго массива и отфильтруйте первый: a.filter(value => !excluded.has(value)). Будут удалены все вхождения запрещённых значений, а порядок и повторы остальных сохранятся. Решение возвращает новый массив. При обычной хеш-реализации ожидаемое время — O(n + m).
Как удалить из массива все значения другого массива, сохранив порядок?
Разность массивов на JavaScript через Set и filter: удаляем все совпадения, сохраняем порядок и повторения остальных элементов, обсуждаем память и мутацию.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Даны массивы a и b. Удалите из a все элементы, значение которых встречается в b. Порядок оставшихся элементов должен сохраниться.
a = [0, 2, 2, 2, 4], b = [2] → [0, 4]
a = [1, 2, 2], b = [1] → [2, 2]
a = [0, 2, 3], b = [1, 2] → [0, 3]
Решение без изменения исходного массива
function difference(a, b) {
const excluded = new Set(b);
return a.filter(value => !excluded.has(value));
}
console.log(difference([0, 2, 2, 2, 4], [2])); // [0, 4]
Set содержит значения, которые нужно исключить. filter последовательно рассматривает элементы a и оставляет только разрешённые. Поэтому все три двойки в первом примере исчезнут, но повторяющиеся разрешённые значения не будут удалены. Пустой b даёт копию a, пустой a — пустой результат.
Сначала стоит уточнить, нужно ли менять сам a. Приведённый вариант возвращает новый массив. Если требуется мутация, можно использовать два индекса:
function differenceInPlace(a, b) {
const excluded = new Set(b);
let write = 0;
for (let read = 0; read < a.length; read++) {
if (!excluded.has(a[read])) {
a[write++] = a[read];
}
}
a.length = write;
return a;
}
Индекс записи не обгоняет чтение, поэтому ещё не проверенные элементы не затираются.
Сложность и сравнение
Для обычной хеш-реализации множества ожидаемое время — O(n + m), где n и m — длины массивов. Память множества — O(m), новый результат первого варианта требует ещё O(n). Это не обещание константного времени Set.has в худшем случае для любой реализации JavaScript.
Решение рассчитано на обычные плотные массивы значений. Для объектов сравниваются ссылки, а не содержимое: два разных объекта {id: 1} не совпадут. NaN совпадает с NaN, а 0 с -0. При сравнении объектов по идентификатору в множество нужно помещать выбранные ключи. Правила равенства описаны в MDN: Set.