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:

result <- integer(ncol(df))
for (k in seq_len(ncol(df)))
    result[k] <- sum(is.na(df[[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().