5.3 Neatomické vektory (seznamy)
Neatomicke vektory (casteji nazyvane seznamy) jsou vektory, jejichz jednotlive prvky mohou mit ruzne datove typy, treba i jine seznamy. Seznamy jsou nekdy uzitecne, protoze umoznuji v jedne promenne skladovat ruzne typy dat. Jejich hlavni vyznam vsak spociva v tom, ze se pouzivaji jako zaklad pro tvorbu vetsiny objektu v systemu S3
, viz kapitola 9.
Seznamy se vytvářejí pomocí funkce list()
:
<- list(1L, 11, 1:3, "ahoj", list(1, 1:3, "ahoj"))
l l
## [[1]]
## [1] 1
##
## [[2]]
## [1] 11
##
## [[3]]
## [1] 1 2 3
##
## [[4]]
## [1] "ahoj"
##
## [[5]]
## [[5]][[1]]
## [1] 1
##
## [[5]][[2]]
## [1] 1 2 3
##
## [[5]][[3]]
## [1] "ahoj"
Stejně jako atomické vektory, i seznamy mohou mít atribut names
, tj. jednotlivé prvky seznamu mohou mít svá jména. Ta se přiřazují stejně jako v případě atomických vektorů:
<- list(a = 1, b = "ahoj", c = 1:3, d = list(1:3, "ahoj"))
l names(l)
## [1] "a" "b" "c" "d"
l
## $a
## [1] 1
##
## $b
## [1] "ahoj"
##
## $c
## [1] 1 2 3
##
## $d
## $d[[1]]
## [1] 1 2 3
##
## $d[[2]]
## [1] "ahoj"
Délku seznamu zjistíme pomocí funkce length()
:
length(l)
## [1] 4
K otestování, zda je proměnná seznam, slouží funkce is.list()
. Funkce is.vector()
vrací hodnotu TRUE
jak pro atomické vektory, tak i pro seznamy.
is.list(l)
## [1] TRUE
is.vector(l)
## [1] TRUE
Strukturu seznamu je možné přehledně zobrazit pomocí funkce str()
. Podobný výsledek dostanete v RStudiu tak, že v záložce Environment
kliknete na trojúhelníček v kolečku vedle jména seznamu. Musíte však být v módu List.
str(l)
## List of 4
## $ a: num 1
## $ b: chr "ahoj"
## $ c: int [1:3] 1 2 3
## $ d:List of 2
## ..$ : int [1:3] 1 2 3
## ..$ : chr "ahoj"
Subsetování seznamů je poněkud složitější, než je tomu u atomických proměnných. Subsetování pomocí hranatých závorek zachovává mód proměnné. To znamená, že použití hranatých závorek na seznam vrací opět seznam. Pokud chceme získat přímo prvek uložený v seznamu, musíme použít dvojité hranaté závorky ([[]]
). Podobnou funkci plní i operátor dolar ($
).
Subsetování seznamu pomocí hranatých závorek vrací prvky opět zabalené do seznamu:
<- list(a = 1, b = 1:3, c = "ahoj")
l l
## $a
## [1] 1
##
## $b
## [1] 1 2 3
##
## $c
## [1] "ahoj"
1] l[
## $a
## [1] 1
is.list(l[1])
## [1] TRUE
1:2] l[
## $a
## [1] 1
##
## $b
## [1] 1 2 3
Pokud chceme získat vlastní prvek seznamu, musíme použít dvojité hranaté závorky. Dvojité hranaté závorky “vybalí” daný prvek ze seznamu ven:
2]] l[[
## [1] 1 2 3
is.list(l[[2]])
## [1] FALSE
is.numeric(l[[2]])
## [1] TRUE
Syntaxe dvojitých hranatých závorek je poněkud nečekaná. Pokud je argumentem vektor, nevrací dvojité hranaté závorky vektor hodnot (to ani nejde, protože výsledkem by musel být opět seznam), nýbrž se vektor přeloží na rekurentní volání dvojitých hranatých závorek:
2]][[3]] # třetí prvek vektoru, který je druhým prvkem seznamu l[[
## [1] 3
2:3]] # totéž l[[
## [1] 3
# protože druhým prvkem seznamu je zde atomický vektor, mohou být druhé závorky jednoduché:
2]][3] l[[
## [1] 3
Pokud jsou prvky seznamu pojmenované, nabízí R zkratku ke dvojitým hranatým závorkám: operátor dolar ($
): l[["b"]]
je totéž jako l$b
:
"b"]] # prvek se jménem b l[[
## [1] 1 2 3
$b # totéž (uvozovky se zde neuvádějí) l
## [1] 1 2 3
Použití dolaru od dvojitých závorek v jednom ohledu liší: pokud máme jméno prvku, který chceme získat uloženo v proměnné, je třeba použít hranaté závorky – operátor dolar zde nelze použít:
<- "c"
element # element není v uvozovkách, protože vybíráme hodnotu, která je v něm uložená:
l[[element]]
## [1] "ahoj"
Pokud indexujeme jménem prvek seznamu, který v seznamu chybí, dostaneme hodnotu NULL
. Pokud jej však indexujeme číselným indexem, dostaneme chybu:
"d"]] l[[
## NULL
$d l
## NULL
4]] # chybný řádek l[[
## Error in l[[4]]: subscript out of bounds
Seznamy umožňují používat i jen části jmen prvků, pokud jsou určeny jednoznačně (tomu se říká “partial matching”). S dolarem partial matching zapnutý vždy; s dvojitými hranatými závorkami jen v případě, že o to požádáte parametrem exact = FALSE
.
<- list(prvni_prvek = 1, druhy_prevk = 2)
l $p l
## [1] 1
"p"]] l[[
## NULL
"p", exact = FALSE]] l[[
## [1] 1
Doporučuji partial matching nikdy nevyužívat – může být zdrojem špatně dohledatelných chyb!