10.3 Filtrace a detekce prvků vektorů

Balík purrr implementuje i několik funkcí určených k filtraci hodnot vektorů. Funkce keep(.x, .p, ...) vrací ty prvky vektoru .x, pro které predikátová funkce .p() vrací hodnotu TRUE. Naopak funkce discard(.x, .p, ...) vrací ty prvky vektoru .x, pro které predikátová funkce .p() vrací hodnotu FALSE, tj. zahazuje prvky, pro které podmínka platí. Funkce head_while(.x, .p, ...) a tail_while(.x, .p, ...) vrací všechny prvky od začátku nebo od konce, pro které funkce .p() souvisle vrací hodnotu TRUE. Ve všech těchto funkcích nemusí být .p funkce: může to být i logický vektor stejné délky jako .x nebo pravostranná formule, která vrací logickou hodnotu. Jejich použití ukazuje následující příklad:

v <- 1:10
is.odd <- function(x) x %% 2 != 0  # vrací TRUE, když je číslo liché
keep(v, is.odd)  # výběr lichých hodnot z vektoru v
## [1] 1 3 5 7 9
keep(v, ~ . %% 2 != 0)  # totéž pomocí pravostranné formule
## [1] 1 3 5 7 9
discard(v, is.odd)  # vrácení vektoru v bez lichých hodnot
## [1]  2  4  6  8 10
head_while(v, ~ . < 5)  # vrácení prvních hodnot menších než 5
## [1] 1 2 3 4

Funkce compact(.x, .p = identity) umožňuje ze seznamu vypustit ty prvky, které mají buď hodnotu NULL nebo nulovou délku.

compact(list(a = 1, b = 2, c = NULL, d = 4, e = numeric(0)))
## $a
## [1] 1
## 
## $b
## [1] 2
## 
## $d
## [1] 4

Parametr .p umožňuje zadat funkci nebo formuli. Pokud tato funkce vrátí NULL nebo prázdný vektor, pak funkce compact() vynechá odpovídající prvek. Zbývající hodnoty však nejsou funkcí .p nijak transformované. Použití ukazuje triviální příklad:

compact(1:5, .p = ~ .[. < 4])  # zachová pouze prvky menší než 4
## [1] 1 2 3

Funkce detect(.x, .f, ..., .dir = c("forward", "backward"), .default = NULL) vrací první položku vektoru .x, pro kterou vrací .f hodnotu TRUE. Funkce detect_index(.x, .f, ..., .dir = c("forward", "backward")) vrací index této položky. Stejně jako výše může .f být funkce nebo pravostranná formule, která vrací logickou hodnotu.

detect(v, is.odd)  # první lichá hodnota ve vektoru v
## [1] 1
detect(v, ~ . > 1)  # první hodnota větší než 1
## [1] 2
detect_index(v, is.odd)  # index prvního lichého prvku vektoru v
## [1] 1
detect_index(v, ~ . > 1)  # index prvního prvku většího než 1
## [1] 2

Dva zbývající parametry určují směr, odkud se budou hodnoty hledat (parametr .dir, implicitně zepředu), a jaká hodnota se vrátí, pokud žádný prvek vektoru nesplňuje zadaný predikát (parametr .default).

Funkce every(.x, .p, ...) a some(.x, .p, ...) zobecňují logické funkce all() a any(). every() vrací TRUE, pokud zadaná predikátová funkce .p vrací pro každý prvek vektoru .x hodnotu TRUE; funkce some() vrací TRUE, pokud .f vrací TRUE aspoň pro jeden prvek .x. Pomocí těchto funkcí můžeme např. otestovat, zda tabulka df obsahuje aspoň jeden numerický sloupec (some()) nebo jen numerické sloupce (every()):

df %>% some(is.numeric)  # obsahuje df aspoň jeden numerický sloupec?
## [1] TRUE
df %>% every(is.numeric)  # obsahuje df pouze numerické sloupce?
## [1] FALSE

Funkce has_element(.x, .y) zobecňuje operátor %in%. Vrací TRUE, pokud vektor .x obsahuje objekt .y.

x <- list(1:5, "a")  # prvky x jsou vektory 1:5 a "a"
has_element(x, 1:5)
## [1] TRUE
has_element(x, 3)
## [1] FALSE

Balík purrr nabízí i užitečnou funkci negate(), která transformuje zadanou funkci tak, že vrací její negaci. Pokud bychom chtěli pomocí keep() a naší funkce is.odd() vybrat sudé prvky, museli bychom použít formuli:

keep(1:10, ~ !is.odd(.))
## [1]  2  4  6  8 10

Pomocí funkce negate() však můžeme negovat celou predikátovou funkci is.odd():

keep(1:10, negate(is.odd))
## [1]  2  4  6  8 10