04.07 Reduce
Výuka
Proč Reduce?
reduce() je metoda, která redukuje celé pole na jednu hodnotu (číslo, string, objekt, nebo i nové pole). Je to nejuniverzálnější, ale také nejtěžší metoda pole.
Proč to potřebujeme?
- Agregace - Součet, průměr, maximum, minimum
- Transformace - Převeď pole na objekt nebo jiný formát
- Složené operace - Kombinuj map, filter a další do jedné iterace
- Accumulation - Nashromáždí výsledky postupně (jako sněhová koule)
Představ si to jako: Stavění sněhuláka. Začneš s malou sněhovou koulí (počáteční hodnota), postupně přidáváš sníh (prvky pole), a nakonec máš velkého sněhuláka (finální hodnota). Každý prvek pole přispěje k výsledku.
Jak to funguje?
reduce(fn, initialValue):
1. Zavolá funkci fn pro každý prvek pole
2. Funkce dostává akumulátor (accumulator) a aktuální prvek
3. Funkce vrací novou hodnotu akumulátoru
4. Akumulátor se "nese" přes všechny iterace
5. Vrací finální hodnotu akumulátoru (ne pole!)
Klíčové koncepty
reduce(reducer, initialValue)- redukuje pole na jednu hodnotu- Reducer - funkce:
(accumulator, element, index, array) => newAccumulator - Accumulator - průběžný výsledek (nese se přes iterace)
- Initial value - počáteční hodnota akumulátoru (důležitá!)
- Univerzální - může nahradit
map,filter, nebo obojí - Výsledek - může být číslo, string, objekt, nebo i nové pole
JavaScript
Příklad 1: Součet čísel (klasický příklad)
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce(function(accumulator, current) {
return accumulator + current;
}, 0);
console.log(sum);
// → 15
// Krok po kroku:
// Iter 1: acc=0, current=1 → return 0+1=1 → acc=1
// Iter 2: acc=1, current=2 → return 1+2=3 → acc=3
// Iter 3: acc=3, current=3 → return 3+3=6 → acc=6
// Iter 4: acc=6, current=4 → return 6+4=10 → acc=10
// Iter 5: acc=10, current=5 → return 10+5=15 → acc=15
// Finální hodnota: 15
Co se stalo?
- Počáteční hodnota:
0(druhý argumentreduce) - Reducer:
(acc, curr) => acc + curr - V každé iteraci se aktuální prvek přičte k akumulátoru
- Finální hodnota akumulátoru je součet všech prvků
Příklad 2: Arrow funkce (kratší syntax)
const numbers = [1, 2, 3, 4, 5];
// Součet
const sum = numbers.reduce((acc, n) => acc + n, 0);
console.log(sum);
// → 15
// Součin
const product = numbers.reduce((acc, n) => acc * n, 1);
console.log(product);
// → 120 (1 * 2 * 3 * 4 * 5)
// Maximum
const max = numbers.reduce((acc, n) => n > acc ? n : acc, numbers[0]);
console.log(max);
// → 5
Co se stalo?
- Součet: start od 0, přičítej prvky
- Součin: start od 1 (ne 0!), násobuj prvky
- Maximum: použij ternární operátor, vrať větší hodnotu
Příklad 3: Spojení textů (concatenation)
const words = ['Hello', 'world', 'from', 'reduce'];
const sentence = words.reduce((acc, word) => acc + ' ' + word, '');
console.log(sentence);
// → ' Hello world from reduce' (pozor na mezeru na začátku!)
// Lepší verze - bez mezery na začátku
const sentence2 = words.reduce((acc, word, index) => {
return acc + (index > 0 ? ' ' : '') + word;
}, '');
console.log(sentence2);
// → 'Hello world from reduce'
// Nebo prostě použij join (jednodušší!)
const sentence3 = words.join(' ');
console.log(sentence3);
// → 'Hello world from reduce'
Co se stalo?
- Můžeš spojovat stringy, ale pozor na počáteční hodnotu
- Často je lepší použít
join()pro spojování textů
Příklad 4: Transformace pole na objekt
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 3, name: 'Charlie' }
];
// Vytvoř objekt indexovaný podle ID
const usersById = users.reduce((acc, user) => {
acc[user.id] = user;
return acc;
}, {});
console.log(usersById);
// → {
// 1: { id: 1, name: 'Alice' },
// 2: { id: 2, name: 'Bob' },
// 3: { id: 3, name: 'Charlie' }
// }
console.log(usersById[2]);
// → { id: 2, name: 'Bob' }
Co se stalo?
- Počáteční hodnota: prázdný objekt
{} - Postupně přidáváme prvky do objektu s klíčem podle ID
- Výsledek: objekt pro rychlé vyhledávání podle ID
Příklad 5: Počítání výskytů (counting)
const fruits = ['jablko', 'banán', 'jablko', 'třešeň', 'banán', 'jablko'];
const count = fruits.reduce((acc, fruit) => {
acc[fruit] = (acc[fruit] || 0) + 1;
return acc;
}, {});
console.log(count);
// → { jablko: 3, banán: 2, třešeň: 1 }
Co se stalo?
- Počáteční hodnota: prázdný objekt
{} - Pro každý prvek: zvyš počet o 1 (nebo nastav na 1, pokud neexistuje)
acc[fruit] || 0- pokud klíč neexistuje, použij 0- Výsledek: objekt s počty výskytů
Příklad 6: Kombinace map + filter (flatten)
const numbers = [1, 2, 3, 4, 5, 6];
// Udělej map + filter najednou pomocí reduce
const result = numbers.reduce((acc, n) => {
if (n % 2 === 0) { // Filtr - jen sudá čísla
acc.push(n * 2); // Map - vynásob dvěma
}
return acc;
}, []);
console.log(result);
// → [4, 8, 12]
// Porovnej s map + filter
const result2 = numbers
.filter(n => n % 2 === 0)
.map(n => n * 2);
console.log(result2);
// → [4, 8, 12]
Co se stalo?
reducemůže nahraditmap+filter- Počáteční hodnota: prázdné pole
[] - Jen jedno procházení pole (vs. dvě u map + filter)
- Ale:
map+filterjsou čitelnější!
TypeScript
TypeScript přidává typovou kontrolu akumulátoru a výsledku.
Stejné příklady s typy
// Součet s typy
const numbers: number[] = [1, 2, 3, 4, 5];
const sum: number = numbers.reduce((acc: number, n: number): number => acc + n, 0);
// TypeScript inferuje typy z počáteční hodnoty
const sum2 = numbers.reduce((acc, n) => acc + n, 0); // acc i n jsou number
// Transformace na objekt
interface User {
id: number;
name: string;
}
const users: User[] = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
];
// Musíš explicitně typovat akumulátor, pokud je jiný typ než prvky pole
const usersById: Record<number, User> = users.reduce((acc, user) => {
acc[user.id] = user;
return acc;
}, {} as Record<number, User>);
// Nebo použij generický typ
const usersById2 = users.reduce<Record<number, User>>((acc, user) => {
acc[user.id] = user;
return acc;
}, {});
// Počítání s explicitním typem
const fruits: string[] = ['jablko', 'banán', 'jablko'];
const count: Record<string, number> = fruits.reduce((acc, fruit) => {
acc[fruit] = (acc[fruit] || 0) + 1;
return acc;
}, {} as Record<string, number>);
// Chybová kontrola - špatný typ počáteční hodnoty
const invalid = numbers.reduce((acc, n) => acc + n, '');
// ❌ Error: Type 'string' is not assignable to type 'number'
// (TypeScript ví, že acc + n by mělo být number, ne string)
TypeScript přidává:
- ✅ Inference typu akumulátoru - z počáteční hodnoty
- ✅ Typovou kontrolu reduceru - acc, current a návratová hodnota musí souhlasit
- ✅ Explicitní generický typ -
reducepro složitější případy() - ✅ Prevenci chyb - nemůžeš vrátit špatný typ z reduceru
Rozdíl JS vs TS
JavaScript:
- reduce funguje bez typové kontroly
- Můžeš omylem změnit typ akumulátoru
- Počáteční hodnota může být cokoli
- Flexibilnější, ale nebezpečnější
TypeScript:
- Typ akumulátoru je inferován nebo explicitně zadaný
- TypeScript zkontroluje, že reducer vrací správný typ
- Lepší dokumentace a prevence chyb
- Bezpečnější, čitelnější
// JavaScript - projde, ale způsobí problém
const numbers = [1, 2, 3];
const result = numbers.reduce((acc, n) => acc + String(n), 0);
// result je '0123' (string!), ne 6
// TypeScript - upozorní na změnu typu
const numbers: number[] = [1, 2, 3];
const result: number = numbers.reduce((acc, n) => acc + String(n), 0);
// ❌ Error: Type 'string' is not assignable to type 'number'
Tip
💡 VŽDY zadávej počáteční hodnotu:
const numbers = [1, 2, 3, 4, 5];
// ✅ S počáteční hodnotou - jasné a bezpečné
const sum = numbers.reduce((acc, n) => acc + n, 0);
// ⚠️ Bez počáteční hodnoty - použije první prvek
const sum2 = numbers.reduce((acc, n) => acc + n); // acc=1, pak 1+2, 3+3, 6+4, 10+5
// ❌ Nebezpečné pro prázdné pole!
const empty = [];
const fail = empty.reduce((acc, n) => acc + n); // TypeError: Reduce of empty array with no initial value
💡 Pro jednoduché případy použij specializované metody:
// ❌ Zbytečně složité
const sum = numbers.reduce((acc, n) => acc + n, 0);
const doubled = numbers.reduce((acc, n) => [...acc, n * 2], []);
// ✅ Čitelnější
const sum = numbers.reduce((acc, n) => acc + n, 0); // OK pro součet
const doubled = numbers.map(n => n * 2); // Lepší pro transformaci
💡 reduce vs map + filter - čitelnost vs výkon:
// ✅ Čitelnější - použij map + filter
const result = numbers
.filter(n => n % 2 === 0)
.map(n => n * 2);
// ⚠️ Rychlejší (jedna iterace), ale méně čitelné
const result = numbers.reduce((acc, n) => {
if (n % 2 === 0) acc.push(n * 2);
return acc;
}, []);
// Pro většinu případů preferuj čitelnost
Kvíz
Co vypíše tento kód?
const arr = [1, 2, 3];
const result = arr.reduce((acc, n) => acc - n);
console.log(result);
❌ - Chybný výpočet
❌ - Není to součet
✅ - BEZ počáteční hodnoty reduce použije první prvek jako acc. Tedy: acc = 1 (první prvek), pak 1 - 2 = -1, pak -1 - 3 = -4
❌ - Není to chyba (ale je to nebezpečné pro prázdná pole!)
Důležité: Bez počáteční hodnoty reduce použije první prvek jako akumulátor a začne od druhého prvku. Toto může způsobit nečekané výsledky! Vždy zadávej počáteční hodnotu.
Důležité: Bez počáteční hodnoty reduce použije první prvek jako akumulátor a začne od druhého prvku. Toto může způsobit nečekané výsledky! Vždy zadávej počáteční hodnotu.
🎯 Závěrečný projekt
Po dokončení všech 8 dílů vytvoříte jednoduchou Todо aplikaci v čistém JavaScriptu. Naučíte se, jak aplikovat vše, co jste se naučili, na reálný projekt.
Zobrazit podrobnosti projektu →Informace o seriálu
Obtížnost
Délka
Cca 480 minut
Počet videí
8 videí + projekty
Certifikát
Po dokončení obdržíte certifikát
Lekce v této sekci
- 04.01 Vytvoření pole
- 04.02 Přístup k prvkům
- 04.03 Push, pop, shift, unshift
- 04.04 Slice a splice
- 04.06 Filter
- 04.07 Reduce
- 04.08 Find a findIndex
- 04.09 Some a every
- 04.10 Sort
- 04.11 Spread operátor
- 04.12 Set
- 04.13 Map kolekce
- 04.14 Destructuring polí
Struktura lekcí (souborový strom)
- 1.1 Úvod do JavaScriptu a TypeScriptu
- 1.2 Nastavení prostředí
- 1.3 První program
- 1.4 Proměnné: var, let, const
- 1.5 Datové typy - přehled
- 1.6 String (řetězce)
- 1.7 Number (čísla)
- 1.8 Boolean (pravda/nepravda)
- 1.9 Null a Undefined
- 1.10 Type Inference vs Annotations
- 1.11 Aritmetické operátory
- 1.12 Porovnávací operátory
- 1.13 Logické operátory
- 1.14 Komentáře
- 1.15 Console metody
- 03.01 Deklarace funkce
- 03.02 Function Expression
- 03.03 Arrow Functions
- 03.04 Parametry a argumenty
- 03.05 Return hodnoty
- 03.06 Výchozí parametry
- 03.07 Rest parametry
- 03.08 Co je Scope
- 03.09 Lexikální Scope
- 03.10 Řetězec Scope
- 03.11 Globální Scope
- 03.12 Životní Cyklus Proměnných
- 03.13 Omezení Scope
- 03.14 Použití Closures
- 03.15 Callback funkce
- 03.16 Higher-order Functions
- 03.17 IIFE
- 03.18 Void funkce
- 03.19 Rekurze
- v přípravě
- v přípravě
- v přípravě
- v přípravě
- 01 — Co je Next.js
- 02 — Vytvoření projektu
- 03 — Struktura projektu (app/)
- 04 — Page komponenty (page.js / page.tsx)
- 05 — Layout komponenty (layout.js / layout.tsx)
- 06 — File-based routing
- 07 — Dynamické routy ([id]/page.js)
- 08 — Link komponenta (navigace)
- 09 — Image komponenta (next/image)
- 10 — Metadata (title, description, Open Graph)
- 11 — Loading UI (loading.js / loading.tsx)
- 12 — Error handling (error.js / error.tsx)
- 13 — Not Found (not-found.js / not-found.tsx)
- v přípravě
- v přípravě
- v přípravě