← Назад к вопросам

Как фильтровать массив без filter?

1.0 Junior🔥 122 комментариев
#JavaScript Core

Комментарии (2)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как фильтровать массив без filter

Метод filter() - это стандартный способ, но есть множество альтернатив. Понимание этих подходов полезно для собеседований и выбора оптимального решения в разных контекстах.

1. Цикл for

Традиционный способ с явной итерацией:

const numbers = [1, 2, 3, 4, 5, 6];
const evenNumbers = [];

for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] % 2 === 0) {
    evenNumbers.push(numbers[i]);
  }
}

console.log(evenNumbers); // [2, 4, 6]

Плюсы:

  • Явный контроль
  • Хорошая производительность
  • Можно break/continue

Минусы:

  • Многословно
  • Нужно управлять индексом

2. Цикл for...of

Современный способ - проще читается:

const numbers = [1, 2, 3, 4, 5, 6];
const evenNumbers = [];

for (const num of numbers) {
  if (num % 2 === 0) {
    evenNumbers.push(num);
  }
}

console.log(evenNumbers); // [2, 4, 6]

Плюсы:

  • Читаемо
  • Доступ к элементу напрямую
  • for...of работает с итерируемыми объектами

Минусы:

  • Нет доступа к индексу (если нужен)

3. for...of с индексом через entries()

Если нужен и элемент, и индекс:

const questions = ['Q1', 'Q2', 'Q3', 'Q4'];
const filtered = [];

for (const [index, question] of questions.entries()) {
  if (question !== 'Q2') {
    filtered.push(question);
  }
}

console.log(filtered); // ['Q1', 'Q3', 'Q4']

4. Метод forEach

Функциональный подход, но нужно управлять внешним массивом:

const numbers = [1, 2, 3, 4, 5, 6];
const evenNumbers = [];

numbers.forEach((num) => {
  if (num % 2 === 0) {
    evenNumbers.push(num);
  }
});

console.log(evenNumbers); // [2, 4, 6]

Плюсы:

  • Функциональный стиль
  • Доступ к index и array

Минусы:

  • Нельзя break
  • Медленнее filter

5. Метод reduce

Мощный метод - накопляет результат:

const numbers = [1, 2, 3, 4, 5, 6];

const evenNumbers = numbers.reduce((acc, num) => {
  if (num % 2 === 0) {
    acc.push(num);
  }
  return acc;
}, []);

console.log(evenNumbers); // [2, 4, 6]

// Или компактнее с спредом
const evenNumbers2 = numbers.reduce(
  (acc, num) => num % 2 === 0 ? [...acc, num] : acc,
  []
);

Плюсы:

  • Универсален (трансформация + фильтрация)
  • Функциональный стиль

Минусы:

  • Медленнее (создание новых массивов со спредом)
  • Может быть сложнее читать

6. Методы concat/spread operator

Комбинирование с условным concat:

const numbers = [1, 2, 3, 4, 5, 6];

const evenNumbers = [].concat(
  ...numbers.map(num => num % 2 === 0 ? [num] : [])
);

console.log(evenNumbers); // [2, 4, 6]

Минусы:

  • Усложнено
  • Медленнее

7. Метод flatMap

Модерный подход - компактен:

const numbers = [1, 2, 3, 4, 5, 6];

const evenNumbers = numbers.flatMap(num =>
  num % 2 === 0 ? [num] : []
);

console.log(evenNumbers); // [2, 4, 6]

Плюсы:

  • Компактно
  • Явно показывает intent (возвращаем массив или пусто)

Минусы:

  • Немного медленнее filter

8. Метод find в цикле

Редко используется, но возможно:

const numbers = [1, 2, 3, 4, 5, 6];
const evenNumbers = [];
let searchFrom = 0;

while (true) {
  const found = numbers.slice(searchFrom).find(num => num % 2 === 0);
  if (!found) break;
  
  evenNumbers.push(found);
  searchFrom = numbers.indexOf(found) + 1;
}

console.log(evenNumbers); // [2, 4, 6]

Очень неэффективно, НЕ используй в production

9. Регулярные выражения (для строк)

Для фильтрации строк по паттерну:

const words = ['apple', 'banana', 'apricot', 'cherry'];
const pattern = /^a/; // Начинаются с 'a'

const filtered = [];
for (const word of words) {
  if (pattern.test(word)) {
    filtered.push(word);
  }
}

console.log(filtered); // ['apple', 'apricot']

10. Метод some/every (для проверок)

Это не фильтрация, но похожие методы:

const numbers = [1, 2, 3, 4, 5, 6];

// Проверить есть ли четные
const hasEven = numbers.some(num => num % 2 === 0);
console.log(hasEven); // true

// Все четные?
const allEven = numbers.every(num => num % 2 === 0);
console.log(allEven); // false

// Если нужен массив результатов - используй filter
const isEven = numbers.map(num => num % 2 === 0);
console.log(isEven); // [false, true, false, true, false, true]

11. Рекурсивная функция

Для понимания алгоритмов (не для production):

function filterRecursive(arr, predicate, index = 0, result = []) {
  if (index >= arr.length) {
    return result;
  }
  
  if (predicate(arr[index])) {
    result.push(arr[index]);
  }
  
  return filterRecursive(arr, predicate, index + 1, result);
}

const numbers = [1, 2, 3, 4, 5, 6];
const evenNumbers = filterRecursive(numbers, num => num % 2 === 0);
console.log(evenNumbers); // [2, 4, 6]

12. Собственная реализация filter

Для понимания как работает фильтрация:

// Собственная реализация filter
Array.prototype.myFilter = function(callback, thisArg) {
  if (this == null) {
    throw new TypeError('this is null or not defined');
  }
  
  const O = Object(this);
  const len = parseInt(O.length) || 0;
  const result = [];
  
  for (let k = 0; k < len; k++) {
    if (k in O) {
      const kValue = O[k];
      if (callback.call(thisArg, kValue, k, O)) {
        result.push(kValue);
      }
    }
  }
  
  return result;
};

const numbers = [1, 2, 3, 4, 5, 6];
const evenNumbers = numbers.myFilter(num => num % 2 === 0);
console.log(evenNumbers); // [2, 4, 6]

Сравнение производительности

const numbers = Array.from({ length: 1000000 }, (_, i) => i);

console.time('filter');
numbers.filter(n => n % 2 === 0);
console.timeEnd('filter'); // ~5ms

console.time('for');
const result = [];
for (const n of numbers) {
  if (n % 2 === 0) result.push(n);
}
console.timeEnd('for'); // ~3ms (быстрее)

console.time('reduce');
numbers.reduce((acc, n) => n % 2 === 0 ? [...acc, n] : acc, []);
console.timeEnd('reduce'); // ~150ms (медленно)

Рекомендации

Используй filter в production:

  • Стандартный способ
  • Читаемо
  • Производительность нормальная

Используй for...of если:

  • Нужен break
  • Максимальная производительность
  • Простая логика

Используй reduce если:

  • Нужна более сложная трансформация
  • Фильтрация + другие операции

Избегай:

  • Рекурсии для больших массивов (stack overflow)
  • Reduce со спредом (медленно)
  • Множественных проходов (map + filter)