
Array.reduce() – jeden trik, który zmieni Twoje podejście do przetwarzania danych
Czas czytania: 5 minut
Zaczynamy – reduce() . Jeśli jesteś jak większość programistów JavaScript, prawdopodobnie używasz map() i filter() na co dzień, ale omijasz reduce() szerokim łukiem. Rozumiem – jego składnia może wydawać się skomplikowana, a dokumentacja często więcej myli niż wyjaśnia. Ale uwierz mi, ten jeden trik może zmienić sposób, w jaki myślisz o przetwarzaniu danych.
Czym jest reduce() i dlaczego go unikamy?
Array.reduce() to metoda, która „redukuje” tablicę do jednej wartości. Brzmi abstrakcyjnie? Tak, i to jest problem. Większość ludzi unika reduce(), bo:
- Składnia wydaje się skomplikowana
- Ciężko zapamiętać kolejność parametrów
- Nie widać od razu, do czego to służy
- Pętle
forwydają się prostsze
Ale prawda jest taka: reduce() to jeden z najpotężniejszych narzędzi w JavaScript. Wszystko, co robisz z map(), filter() czy pętlami, możesz zrobić z reduce(). I często będzie to bardziej eleganckie.
Praktyczny przykład: koszyk e-commerce
Zamiast abstrakcyjnych przykładów, pokażę ci coś z prawdziwego życia. Masz koszyk zakupowy i chcesz obliczyć łączną kwotę:
const cart = [
{ name: 'Laptop', price: 2999, quantity: 1 },
{ name: 'Mouse', price: 89, quantity: 2 },
{ name: 'Keyboard', price: 299, quantity: 1 }
];
// Tradycyjny sposób z pętlą for
let total = 0;
for (let i = 0; i < cart.length; i++) {
total += cart[i].price * cart[i].quantity;
}
console.log(total); // 3476
// Z reduce() - krócej i czytelniej
const total = cart.reduce((sum, item) => {
return sum + (item.price * item.quantity);
}, 0);
console.log(total); // 3476
Już widzisz różnicę? Reduce() mówi wprost: „weź tę tablicę i zredukuj ją do jednej liczby”.
Krok po kroku – od prostego do zaawansowanego
Zacznijmy od podstaw. Składnia reduce() to:
array.reduce(callback, initialValue)
1: Proste sumowanie
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, current) => acc + current, 0);
console.log(sum); // 15
2: Znajdowanie maksimum
const numbers = [23, 45, 12, 78, 34];
const max = numbers.reduce((max, current) => {
return current > max ? current : max;
}, numbers[0]);
console.log(max); // 78
3: Grupowanie danych
const users = [
{ name: 'Anna', department: 'IT' },
{ name: 'Jan', department: 'HR' },
{ name: 'Maria', department: 'IT' },
{ name: 'Tomek', department: 'Finance' }
];
const grouped = users.reduce((acc, user) => {
if (!acc[user.department]) {
acc[user.department] = [];
}
acc[user.department].push(user.name);
return acc;
}, {});
console.log(grouped);
// {
// IT: ['Anna', 'Maria'],
// HR: ['Jan'],
// Finance: ['Tomek']
// }
4: Zliczanie wystąpień
const fruits = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple'];
const count = fruits.reduce((acc, fruit) => {
acc[fruit] = (acc[fruit] || 0) + 1;
return acc;
}, {});
console.log(count); // { apple: 3, banana: 2, orange: 1 }
3 najczęstsze błędy i jak ich uniknąć
1: Zapominanie o wartości początkowej
// ŹLE - może nie działać dla pustych tablic
const sum = numbers.reduce((acc, curr) => acc + curr);
// DOBRZE - zawsze podawaj wartość początkową
const sum = numbers.reduce((acc, curr) => acc + curr, 0);
2: Mutowanie akumulatora
// ŹLE - mutuje oryginalny obiekt
const result = data.reduce((acc, item) => {
acc.push(item.name);
return acc;
}, originalArray); // mutuje originalArray!
// DOBRZE - zawsze nowy obiekt/tablica
const result = data.reduce((acc, item) => {
return [...acc, item.name];
}, []);
3: Niepotrzebne komplikowanie
// ŹLE - reduce() nie zawsze jest najlepszy
const doubled = numbers.reduce((acc, num) => [...acc, num * 2], []);
// DOBRZE - użyj map() do transformacji 1:1
const doubled = numbers.map(num => num * 2);
Kiedy użyć reduce(), a kiedy zwykłą pętlę?
Użyj reduce() gdy:
- Chcesz przekształcić tablicę w jedną wartość (liczbę, string, obiekt)
- Pracujesz z metodami funkcyjnymi (map, filter, reduce)
- Chcesz łączyć operacje w jedną linię
- Kod ma być deklaratywny, nie imperatywny
Użyj pętli for/while gdy:
- Potrzebujesz przerwać iterację wcześniej (
break) - Chcesz lepszą wydajność dla dużych zbiorów danych
- Logika jest bardzo złożona i reduce() ją zaciemnia
- Pracujesz z programistami, którzy nie znają reduce()
Bonus: reduce() zamiast map() + filter()
Czasem możesz połączyć map() i filter() w jedną operację:
const products = [
{ name: 'Laptop', price: 2999, category: 'electronics' },
{ name: 'Book', price: 29, category: 'books' },
{ name: 'Phone', price: 1299, category: 'electronics' },
{ name: 'Magazine', price: 15, category: 'books' }
];
// Tradycyjnie: filter() + map()
const expensiveElectronics = products
.filter(p => p.category === 'electronics' && p.price > 1000)
.map(p => p.name);
// Z reduce() - jedna iteracja zamiast dwóch
const expensiveElectronics = products.reduce((acc, product) => {
if (product.category === 'electronics' && product.price > 1000) {
acc.push(product.name);
}
return acc;
}, []);
console.log(expensiveElectronics); // ['Laptop', 'Phone']
Czy to zawsze lepsze? Niekoniecznie. Pierwsza wersja jest bardziej czytelna, ale druga jest wydajniejsza dla dużych zbiorów danych.
Ćwiczenie do samodzielnego wykonania
Spróbuj rozwiązać ten problem używając reduce():
Zadanie: Masz tablicę transakcji bankowych. Oblicz saldo końcowe oraz znajdź największą pojedynczą wpłatę.
const transactions = [
{ type: 'deposit', amount: 1000 },
{ type: 'withdrawal', amount: 250 },
{ type: 'deposit', amount: 500 },
{ type: 'withdrawal', amount: 100 },
{ type: 'deposit', amount: 750 }
];
// Twoje rozwiązanie tutaj
const result = transactions.reduce((acc, transaction) => {
// ???
}, { balance: 0, maxDeposit: 0 });
Rozwiązanie:
const result = transactions.reduce((acc, transaction) => {
if (transaction.type === 'deposit') {
acc.balance += transaction.amount;
acc.maxDeposit = Math.max(acc.maxDeposit, transaction.amount);
} else {
acc.balance -= transaction.amount;
}
return acc;
}, { balance: 0, maxDeposit: 0 });
console.log(result); // { balance: 1900, maxDeposit: 1000 }
Podsumowanie
Array.reduce() to nie tylko metoda do sumowania liczb. To potężne narzędzie do przekształcania danych, które może zastąpić wiele pętli i kombinacji map()/filter(). Kluczem jest zrozumienie, że reduce() zawsze zwraca jedną wartość – czy to liczbę, string, tablicę czy obiekt.
Następnym razem, gdy będziesz chciał przekształcić tablicę w coś innego, pomyśl o reduce(). Może okazać się, że ta „straszna” metoda stanie się twoim ulubionym narzędziem.
Więcej o tej metodzie przeczytasz w artykule: Array.prototype.reduce()
Czy ten post był pomocny? Podziel się nim z innymi programistami, którzy mogą bać się reduce(). A jeśli masz pytania lub własne triki z reduce(), napisz w komentarzach!
Zostaw Komentarz