Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Как фильтровать массив без 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)