10.8 Srovnání map() s cyklem for
Většinu začátečníků funkce typu map()
děsí a snaží se daný problém řešit pomocí cyklů. To je samozřejmě možné. Vraťme se k příkladu, kdy máme nějakou tabulku a chceme zjistit, kolik který její sloupec obsahuje chybějících hodnot.
Pomocí funkce map_int()
to uděláme na jednom řádku:
map_int(df, ~ sum(is.na(.)))
## names income rent loan
## 0 0 0 0
Pokud budeme místo toho chtít použít cyklus for
, bude náš kód vypadat takto:
<- integer(ncol(df))
result for (k in seq_len(ncol(df)))
<- sum(is.na(df[[k]]))
result[k] names(result) <- names(df)
result
## names income rent loan
## 0 0 0 0
Výsledek je v obou případech stejný, ale kód napsaný pomocí cyklů má několik nevýhod: 1) Kód napsaný pomocí cyklu for
bývá obvykle delší a podstatně méně přehledný. Funkce map()
jasně ukazuje, na jakých datech se iteruje a co se na nich iteruje. V kódu cyklu to není zdaleka tak jasně vidět. 2) Při použití cyklu for
musíte myslet na víc věcí: musíte si předalokovat vektor pro uložení výsledku, musíte vektor pojmenovat (pokud o to stojíte) a musíte přemýšlet, jestli použijete jednoduché nebo dvojité hranaté závorky (podle toho, zda je původní vektor a výsledek atomický vektor, seznam, nebo tabulka typu data.frame nebo tibble). 3) Zaplevelíte si pracovní prostředí nechtěnými proměnnými: možná proměnnou result
, určitě však počítadlem cyklu k
. A 4) Mapovací funkce je mnohem jednodušší paralelizovat. Obecně je proto lepší vždy používat funkce typu map()
raději než explicitní cyklus for
.
Přesto však existují situace, kdy je využití cyklů nezbytné. Hlavní případy jsou dva: 1) Když výpočet \(i\)-té hodnoty záleží na některé z hodnot spočítaných dříve a 2) když pro ušetření času nahrazujeme hodnoty přímo v původní datové struktuře, místo abychom celou strukturu vytvářeli znovu. V ostatních situacích je téměř vždy rozumnější použít některou z funkcí typu map()
.