Bekerja dengan kamus / daftar di R

93

Saya punya pertanyaan sepele: Saya tidak bisa menemukan struktur data kamus di R, jadi saya menggunakan daftar sebagai gantinya (seperti "kata" -> angka) Jadi, sekarang saya punya masalah bagaimana cara mendapatkan daftar kunci. Ada yang tahu?

Ivri
sumber

Jawaban:

121

Ya, listjenisnya adalah perkiraan yang bagus. Anda dapat menggunakan names()di daftar Anda untuk mengatur dan mengambil 'kunci':

> 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"
> 
Dirk Eddelbuettel
sumber
18
1 untuk menjawab pertanyaan tanpa sepatah kata pun tentang pendekatan OP yang tidak efektif.
Marek
3
Bergantung pada tujuan penggunaan daftar sebagai proxy untuk kamus, mungkin bijaksana untuk mengingat bahwa pencarian "kunci" untuk daftar adalah O (n) daripada O (1), yang Anda harapkan kamus (yang memiliki kunci hash).
egnha
4
Ya, environmenttipe ini digunakan untuk yang di R, tapi kurang umum / kurang dikenal.
Dirk Eddelbuettel
58

Anda bahkan tidak memerlukan daftar jika nilai "angka" Anda semuanya dalam mode yang sama. Jika saya mengambil contoh 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"

Daftar hanya diperlukan jika nilai Anda dalam mode campuran (misalnya karakter dan angka) atau vektor.

Untuk daftar dan vektor, elemen individu dapat disubset dengan nama:

> foo["tac"]
tac 
 22 

Atau untuk daftar:

> foo[["tac"]]
[1] 22
Calimo
sumber
1
Bagaimana Anda bisa mendapatkan daftar c(12,22,33)dari struktur R bergaya kamus ini? unlist(lapply(FUN=function(a){foo[[a]]},X = 1:length(foo)))sangat merepotkan. Ada fungsi yang siap untuk ini? Pindah pertanyaan ke sini
hhh
18

Untuk memperluas sedikit jawaban Calimo, saya menyajikan beberapa hal lagi yang mungkin berguna bagi Anda saat membuat kamus kuasi ini di R:

a) bagaimana mengembalikan semua NILAI kamus:

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

b) periksa apakah kamus BERISI KUNCI:

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

c) cara MENAMBAHKAN kunci BARU, pasangan nilai ke kamus:

c (foo, tic2 = 44)

hasil:

tic       tac       toe     tic2
12        22        33        44 

d) bagaimana memenuhi persyaratan KAMUS NYATA - bahwa kunci TIDAK DAPAT mengulang (KUNCI UNIK)? Anda perlu menggabungkan b) dan c) dan fungsi build yang memvalidasi apakah ada kunci seperti itu, dan melakukan apa yang Anda inginkan: mis. Jangan izinkan penyisipan, perbarui nilai jika yang baru berbeda dari yang lama, atau buat kembali kunci entah bagaimana (mis. menambahkan beberapa nomor sehingga unik)

e) cara MENGHAPUS pasangan DENGAN KUNCI dari kamus:

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

andilabs
sumber
Dapatkah saya menambahkan kunci yang berisi spasi, seperti 'kunci aneh'?
pengguna1700890
Juga sesuatu seperti ini tidak berhasil c(foo, tic2=NULL). Ada pekerjaan di sekitar?
pengguna1700890
15

Alasan pertama menggunakan kamus adalah kinerja. Meskipun benar bahwa Anda dapat menggunakan vektor dan daftar bernama untuk tugas tersebut, masalahnya adalah vektor tersebut menjadi sangat lambat dan haus memori dengan lebih banyak data.

Namun yang tidak diketahui banyak orang adalah bahwa R memang memiliki struktur data kamus yang terpasang: lingkungan dengan opsihash = TRUE

Lihat contoh berikut untuk membuatnya bekerja:

# 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

Sunting : Atas dasar jawaban ini saya menulis posting blog dengan beberapa konteks lebih: http://blog.ephorie.de/hash-me-if-you-can

vonjd
sumber
Apakah ini berfungsi untuk relasi multvalued? Misalnya tic = 1 dan tic = 17
skan
@skan: Mengapa Anda tidak mencobanya?
vonjd
Menggunakan pendekatan ini sebagai pengganti penggunaan daftar dengan nama mempersingkat waktu lari saya dari 6 menit menjadi 1 detik! Saya mengerti hash baik-baik saja, tetapi adakah yang bisa mengonfirmasi ketika mencari nama dalam daftar algo pencarian macam apa yang digunakan? Apakah ini hanya mengulangi daftar di bawah nama yang cocok? Saya ingin memahami dengan tepat mengapa daftar sangat lambat, serta mengapa hash begitu cepat untuk sejumlah besar kunci?
Phil
@vonjd Saya mencoba menggunakan kamus di R dan menemukan implementasi ini. Namun, apakah ini juga berfungsi ketika setiap nilai dikaitkan dengan sepasang kunci? Terima kasih sebelumnya.
selamatkan
@shana: Bisakah Anda memberikan contoh tentang apa yang Anda maksud sebenarnya?
vonjd
9

Hash paket sekarang tersedia: https://cran.r-project.org/web/packages/hash/hash.pdf

Contoh

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"
Ngọc Linh Vũ
sumber
Bagaimana Anda bisa menambahkan banyak nilai? Saya sudah mencoba dengan mengulang kunci tetapi hanya menyimpan nilai terakhir. Saya juga mencoba menetapkan daftar tetapi tidak berhasil
skan
Kamus tidak pernah menyimpan banyak nilai per kunci. Anda dapat menetapkan daftar ke kunci jika Anda mau.
BallpointBen
7

Variasi yang lebih pendek dari jawaban 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"
Jelatang
sumber
4

Saya hanya akan berkomentar bahwa Anda bisa mendapatkan banyak manfaat tablesaat mencoba "memalsukan" kamus juga, misalnya

> 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"

dll.

Gabriel Perdue
sumber
Saya rasa tidak as.numeric()perlu. Tabel sudah berupa angka. Anda bisa mendapatkan hasil yang sama dengannames(t[order(t)])
Rich Scriven