清單

清單 在 R

1 個練習

關於 清單

R 中的list是有序的項目集合,和vectors有幾點不同:

  • 項目可以是不同的型態(例如把numeric和character混在一起)。
  • 項目可以是複雜的結構(例如 vector、其他 list 等等)。
  • 存取元素時,語法也有些不同。

和其他語言類比並不精確。R 的list有點像 Python 的字典,但list是有序的,而且可以用數值索引存取。它也有點像 C 的struct,差別在於list可以輕鬆地在執行階段擴充。

建立 list

為元素加上名稱(常稱為「標籤」),在 list 中比在 vector 中更常見:

list(x = 5.3, y = 4.2, color = "blue")
#> $x
#> [1] 5.3

#> $y
#> [1] 4.2

#> $color
#> [1] "blue"

不過標籤是選用的,如果不加標籤,R 就只會使用索引編號:

list(5.3, 4.2, "blue")
#> [[1]]
#> [1] 5.3

#> [[2]]
#> [1] 4.2

#> [[3]]
#> [1] "blue"

存取 list 元素

有三種做法,各自適合不同的情境。

1. 使用$tag標記法

如果事先就知道標籤名稱,這種寫法非常常見。

point <- list(x = 5.3, y = 4.2, color = "blue")
#> point$x
#> [1] 5.3
#> point$color
#> [1] "blue"

2. 使用[[tag]]標記法

這種寫法的優點是,標籤名稱可以在執行階段才決定。請注意這裡用的是雙重方括號。

want <- "y"
point[[want]] # same as point$y
#> [1] 4.2

3. 使用位置索引

不論 list 有沒有標籤,這種方式都能用。同樣地,這裡的括號要寫成雙重。

point[[3]] # same as point$color
#> [1] "blue"

新增與刪除元素

很簡單:對元素指定值時,如果它已經存在就會被修改,如果是新的就會被插入。

point$color <- "red"
point$trust <- TRUE

# str() gives more compact output than the default display
str(point) 
#> List of 4
#>  $ x    : num 5.3
#>  $ y    : num 4.2
#>  $ color: chr "red"
#>  $ trust: logi TRUE

要刪除元素,只要把不想要的元素指定成NULL。

point$trust <- NULL
str(point)  
#> List of 3
#>  $ x    : num 5.3
#>  $ y    : num 4.2
#>  $ color: chr "red"

list 是「遞迴向量」

vector類別在技術上稱為atomic vector,因為它只能存放原子值:numeric、character、boolean等等。由於list可以包含其他的 list,所以也稱為recursive vector。

這除了是術語命名上的技術重點,也提醒我們 list 可以有任意複雜的結構。存取 list 元素時會拿到什麼,得由程式設計者自己負責弄清楚。

更多關於 list 索引

前面有些例子用了雙重方括號[[ ]]來存取 list 元素。這種寫法會試著把元素攤平成它底層的型態,如果你只想要一個數字或字串,就很方便。

使用單一括號[ ]則不會攤平,回傳的值會是一個子 list。

point[["color"]]
#> [1] "red"  # flattened

point["color"]
#> $color
#> [1] "red"  # sublist

即使子 list 不是 R 新手會想要的結果,也請留意這種行為。為了最大的彈性,許多 R 的標準函式會回傳list,即使它像這裡一樣只包含單一個原子值。

要轉換成 vector 有兩種做法。

  1. 用[[1]]取出第一個元素
  2. 使用unlist()函式
pt <-point["color"]

pt[[1]]
#> [1] "red" # simple 1-element vector

unlist(pt)
#> color 
#> "red"  # 1-element vector with name

使用unlist()時要小心喔。在這個簡單的例子裡,攤平結構很方便,但如果 list 元素比較複雜,就可能帶來意想不到的結果。

Advanced

內部表示法

list和原子vector一樣是連續儲存的。差別在於,數值向量和布林向量儲存的是值,而 list 儲存的是記憶體中其他位置物件的參照。

對 R 使用者來說,知道這件事通常不太重要;但在像 Exercism 這樣的多語言社群裡,對熟悉其他語言的程式設計者可能會有幫助。

透過 GitHub 編輯 連結會在新視窗或分頁中開啟

學習 清單