Làm việc với từ điển / danh sách trong R


89

Tôi có một câu hỏi nhỏ: Tôi không thể tìm thấy cấu trúc dữ liệu từ điển trong R, vì vậy tôi đã sử dụng danh sách thay thế (như "từ" -> số) Vì vậy, ngay bây giờ tôi có vấn đề làm thế nào để lấy danh sách khóa. Có ai biết không?

Câu trả lời:


118

Có, listloại này là một ước lượng tốt. Bạn có thể sử dụng names()trong danh sách của mình để đặt và truy xuất các 'khóa':

> foo <- vector(mode="list", length=3)
> names(foo) <- c("tic", "tac", "toe")
> foo[[1]] <- 12; foo[[2]] <- 22; foo[[3]] <- 33
> foo
$tic
[1] 12

$tac
[1] 22

$toe
[1] 33

> names(foo)
[1] "tic" "tac" "toe"
> 

18
+1 để trả lời câu hỏi không có lời về cách tiếp cận không hiệu quả của OP.
Marek

3
Tùy thuộc vào mục đích sử dụng của danh sách làm proxy cho từ điển, có thể cần lưu ý rằng tra cứu "khóa" cho danh sách là O (n) chứ không phải O (1), đó là những gì bạn mong đợi. một từ điển (băm các khóa).
egnha

4
Có, environmentloại được sử dụng cho điều đó trong R, nhưng nó ít phổ biến hơn / ít được biết đến hơn.
Dirk Eddelbuettel

56

Bạn thậm chí không cần danh sách nếu tất cả các giá trị "số" của bạn đều ở cùng một chế độ. Nếu tôi lấy ví dụ của Dirk Eddelbuettel:

> foo <- c(12, 22, 33)
> names(foo) <- c("tic", "tac", "toe")
> foo
tic tac toe
 12  22  33
> names(foo)
[1] "tic" "tac" "toe"

Danh sách chỉ được yêu cầu nếu giá trị của bạn ở chế độ hỗn hợp (ví dụ: ký tự và số) hoặc vectơ.

Đối với cả danh sách và vectơ, một phần tử riêng lẻ có thể được tập hợp con bằng tên:

> foo["tac"]
tac 
 22 

Hoặc cho một danh sách:

> foo[["tac"]]
[1] 22

1
Làm thế nào bạn có thể lấy danh sách c(12,22,33)cấu trúc R kiểu từ điển này foo? unlist(lapply(FUN=function(a){foo[[a]]},X = 1:length(foo)))là rất bất tiện. Bất kỳ chức năng sẵn sàng cho điều này? Đã chuyển câu hỏi ở đây
hhh

18

Để mở rộng một chút câu trả lời của Calimo, tôi trình bày thêm một số điều bạn có thể thấy hữu ích khi tạo từ điển gần như này trong R:

a) cách trả về tất cả các GIÁ TRỊ của từ điển:

>as.numeric(foo)
[1] 12 22 33

b) kiểm tra xem từ điển CHỨA TỪ KHÓA:

>'tic' %in% names(foo)
[1] TRUE

c) cách THÊM khóa, cặp giá trị MỚI vào từ điển:

c (foo, tic2 = 44)

các kết quả:

tic       tac       toe     tic2
12        22        33        44 

d) làm thế nào để đáp ứng yêu cầu của TỪ ĐIỂN THỰC - rằng các phím KHÔNG THỂ lặp lại (PHÍM DUY NHẤT)? Bạn cần kết hợp b) và c) và xây dựng hàm xác nhận xem có khóa như vậy hay không và làm những gì bạn muốn: ví dụ: không cho phép chèn, cập nhật giá trị nếu cái mới khác với cái cũ hoặc xây dựng lại khóa nào đó (ví dụ: thêm một số số vào nó để nó là duy nhất)

e) cách XÓA cặp BẰNG PHÍM khỏi từ điển:

foo <-foo [which (foo! = foo [["tac"]])]


Tôi có thể thêm khóa chứa khoảng trắng, chẳng hạn như 'khóa lạ'?
user1700890

Ngoài ra một cái gì đó như thế này không hoạt động c(foo, tic2=NULL). Bất kỳ công việc xung quanh?
dùng1700890

15

Lý do sử dụng từ điển ngay từ đầu là hiệu suất. Mặc dù đúng là bạn có thể sử dụng các vectơ và danh sách được đặt tên cho tác vụ nhưng vấn đề là chúng đang trở nên khá chậm và bộ nhớ đói với nhiều dữ liệu hơn.

Tuy nhiên, điều mà nhiều người không biết là R thực sự có cấu trúc dữ liệu từ điển có sẵn: môi trường với tùy chọnhash = TRUE

Xem ví dụ sau để biết cách làm cho nó hoạt động:

# vectorize assign, get and exists for convenience
assign_hash <- Vectorize(assign, vectorize.args = c("x", "value"))
get_hash <- Vectorize(get, vectorize.args = "x")
exists_hash <- Vectorize(exists, vectorize.args = "x")

# keys and values
key<- c("tic", "tac", "toe")
value <- c(1, 22, 333)

# initialize hash
hash = new.env(hash = TRUE, parent = emptyenv(), size = 100L)
# assign values to keys
assign_hash(key, value, hash)
## tic tac toe 
##   1  22 333
# get values for keys
get_hash(c("toe", "tic"), hash)
## toe tic 
## 333   1
# alternatively:
mget(c("toe", "tic"), hash)
## $toe
## [1] 333
## 
## $tic
## [1] 1
# show all keys
ls(hash)
## [1] "tac" "tic" "toe"
# show all keys with values
get_hash(ls(hash), hash)
## tac tic toe 
##  22   1 333
# remove key-value pairs
rm(list = c("toe", "tic"), envir = hash)
get_hash(ls(hash), hash)
## tac 
##  22
# check if keys are in hash
exists_hash(c("tac", "nothere"), hash)
##     tac nothere 
##    TRUE   FALSE
# for single keys this is also possible:
# show value for single key
hash[["tac"]]
## [1] 22
# create new key-value pair
hash[["test"]] <- 1234
get_hash(ls(hash), hash)
##  tac test 
##   22 1234
# update single value
hash[["test"]] <- 54321
get_hash(ls(hash), hash)
##   tac  test 
##    22 54321

Chỉnh sửa : Trên cơ sở câu trả lời này, tôi đã viết một bài đăng trên blog với một số ngữ cảnh khác: http://blog.ephorie.de/hash-me-if-you-can


Nó có hoạt động cho các mối quan hệ được đánh giá cao không? Ví dụ: tic = 1 và tic = 17
skan

@skan: Tại sao bạn không dùng thử?
vonjd

Sử dụng cách tiếp cận này thay cho việc sử dụng danh sách có tên đã giảm thời gian chạy của tôi từ 6 phút xuống 1 giây! Tôi hiểu hàm băm là tốt, nhưng có ai có thể xác nhận khi tra cứu tên trong danh sách loại thuật toán tìm kiếm nào được sử dụng không? Đây có phải chỉ là lặp lại danh sách dưới tên các trận đấu? Tôi muốn hiểu chính xác lý do tại sao danh sách quá chậm, cũng như tại sao băm quá nhanh đối với số lượng lớn khóa?
Phil

@vonjd Tôi đang cố gắng sử dụng từ điển trong R và tìm thấy cách triển khai này. Tuy nhiên, nó cũng hoạt động khi mỗi giá trị được liên kết với một cặp khóa? Cảm ơn bạn trước.
savi

@shana: Bạn có thể cho một ví dụ về ý của bạn chính xác không?
vonjd

9

Gói băm hiện đã có sẵn: https://cran.r-project.org/web/packages/hash/hash.pdf

Ví dụ

h <- hash( keys=letters, values=1:26 )
h <- hash( letters, 1:26 )
h$a
# [1] 1
h$foo <- "bar"
h[ "foo" ]
# <hash> containing 1 key-value pair(s).
#   foo : bar
h[[ "foo" ]]
# [1] "bar"

Làm thế nào bạn có thể thêm nhiều giá trị? Tôi đã thử lặp lại khóa nhưng nó chỉ lưu giá trị cuối cùng. Tôi cũng đã thử chỉ định danh sách nhưng nó không hoạt động
skan

Từ điển không bao giờ lưu trữ nhiều giá trị cho mỗi khóa. Bạn có thể gán danh sách cho một khóa nếu bạn muốn.
BallpointBen

7

Biến thể ngắn hơn của câu trả lời Dirk:

# Create a Color Palette Dictionary 
> color <- c('navy.blue', 'gold', 'dark.gray')
> hex <- c('#336A91', '#F3C117', '#7F7F7F')

> # Create List
> color_palette <- as.list(hex)
> # Name List Items
> names(color_palette) <- color
> 
> color_palette
$navy.blue
[1] "#336A91"

$gold
[1] "#F3C117"

$dark.gray
[1] "#7F7F7F"

4

Tôi sẽ chỉ nhận xét rằng bạn có thể nhận được rất nhiều điều tablekhi cố gắng "giả mạo" một từ điển, ví dụ:

> x <- c("a","a","b","b","b","c")
> (t <- table(x))
x
a b c 
2 3 1 
> names(t)
[1] "a" "b" "c"
> o <- order(as.numeric(t))
> names(t[o])
[1] "c" "a" "b"

Vân vân.


Tôi không nghĩ as.numeric()là cần thiết. Bảng đã là số. Bạn có thể nhận được kết quả tương tự vớinames(t[order(t)])
Giàu Scriven
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.