Как удалить из массива все значения другого массива, сохранив порядок?

Разность массивов на JavaScript через Set и filter: удаляем все совпадения, сохраняем порядок и повторения остальных элементов, обсуждаем память и мутацию.

Короткий ответ

Что ответить на собеседовании

Создайте Set из второго массива и отфильтруйте первый: a.filter(value => !excluded.has(value)). Будут удалены все вхождения запрещённых значений, а порядок и повторы остальных сохранятся. Решение возвращает новый массив. При обычной хеш-реализации ожидаемое время — O(n + m).

Подробный разбор

Ответ с пояснениями

Условие

Даны массивы 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.

Практика в реальном времени

Подготовьтесь к следующему собеседованию

Interview Boost учитывает вакансию, резюме и технологии и помогает сформулировать ответ прямо во время интервью.

Начать подготовку