Мой последний пост касался рекурсивного Array.map. Хотя это хороший учебный ресурс, я не рекомендую никому использовать его в своих приложениях.

То же самое касается рекурсивной реализации Array.filter.

Вместо этой (упрощенной) традиционной версии:

filter = (predicate, arr) => {
    const filteredArray = [];
    for (let i = 0; i < arr.length; i++) {
        let currentItem = arr[i];
        if (predicate(currentItem)) {
            filteredArray.push(currentItem);
        }
    }
    return filteredArray;
};

Учти это:

filter = (pred, [head, ...tail]) => head === undefined ? [] : (
 pred(head) ? [head, ...filter(pred, tail)] : [...filter(pred, tail)]
);

Если вы понимаете рекурсивный массив.map, это просто.

Мы по-прежнему фиксируем первый элемент массива в переменной с именем head, а остальные - в отдельный массив с именем tail.

И в том же базовом случае - если head равно undefined, вернуть пустой массив и завершить итерацию.

Но у нас есть еще один условный оператор: помещайте head в новый массив, только если pred(head) равно true, потому что filter работает, проверяя каждый элемент на соответствие функции предиката. Только когда предикат возвращает true, мы добавляем этот элемент в новый массив.

Если pred(head) не возвращает true, просто позвоните filter(pred, tail) без head.

Давайте быстро рассмотрим это в консоли Chrome.

filter = (pred, [head, ...tail]) => {
    if (head === undefined) return [];
    if (pred(head)) {
        debugger;
        return [head, ...filter(pred, tail)];
    }
    debugger;
    return [...filter(pred, tail)];
};

И ищем числа ≤ 10:

filter(x => x <= 10, [1, 10, 20]);

Поскольку [1, 10, 20] нашего массива, head - это первый элемент, 1, а tail - это массив остальных: [10, 20].

Предикат проверяет, x ≤ 10, поэтому pred(1) возвращает true. Вот почему мы приостановили выражение debugger в строке 4.

Поскольку текущий head прошел проверку, ему разрешен вход в наш фильтрованный массив. Но мы еще не закончили, поэтому мы снова вызываем filter с тем же предикатом, а теперь tail.

Перейти к следующему debugger.

Мы позвонили в filter с [10, 20], поэтому head теперь 10, а tail [20]. Так как же tail становится меньше с каждой последующей итерацией?

Мы снова на строке 4 debugger, потому что 10 ≤ 10. Переходим к следующей точке останова.

head сейчас 20, а tail пусто.

Начиная с 20 ›10, pred(head) возвращает false, и наш фильтрованный массив не будет включать его. Мы еще раз позвоним filter без head.

В следующий раз, однако, filter выйдет из строя в строке 2. Разрушение пустого массива даст вам undefined переменных. Пройдите мимо этой точки останова, чтобы получить возвращаемое значение.

Мне это кажется правильным!

Прокомментируйте, если это помогло. Следующим, вероятно, будет рекурсивный reduce. 😁

Продолжайте кодировать. До скорого!

Береги себя,
Язид Бзадоу