R dilinde sözlükler / listelerle çalışma


93

Önemsiz bir sorum var: R'de bir sözlük veri yapısı bulamadım, bu yüzden onun yerine listeyi kullandım ("kelime" -> sayı gibi) Yani, şu anda anahtarların listesini nasıl alacağım konusunda sorun yaşıyorum. Bilen var mı?

Yanıtlar:


121

Evet, listtip iyi bir yaklaşımdır. Sen kullanabilirsiniz names()setine listenizde ve 'tuşlarını' almak:

> 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
OP'nin etkisiz yaklaşımı hakkında tek kelime etmeden soruyu cevaplamak için +1.
Marek

3
Listenin bir sözlük için bir proxy olarak amaçlanan kullanımına bağlı olarak, listeler için "anahtar" aramasının O (1) yerine O (n) olduğunu akılda tutmak akıllıca olabilir. bir sözlük (anahtarların karma olduğu).
egnha

4
Evet, environmenttür R'de bunun için kullanılır, ancak daha az yaygın / daha az bilinir.
Dirk Eddelbuettel

58

"Sayı" değerleriniz aynı moddaysa listelere bile ihtiyacınız yoktur. Dirk Eddelbuettel'in örneğini ele alırsam:

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

Listeler yalnızca değerleriniz karma mod (örneğin karakterler ve sayılar) veya vektörlerden oluşuyorsa gereklidir.

Hem listeler hem de vektörler için, tek bir öğe ada göre alt gruplara ayrılabilir:

> foo["tac"]
tac 
 22 

Veya bir liste için:

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

1
c(12,22,33)Bu sözlük tarzı R yapısı foo'nun listesini nasıl elde edebilirsiniz ? unlist(lapply(FUN=function(a){foo[[a]]},X = 1:length(foo)))çok zahmetli. Bunun için hazır bir işlev var mı? Soruyu buraya
taşıdı

18

Biraz Calimo cevabını genişletmek için, bu sözde sözlükleri R'de oluştururken yararlı bulabileceğiniz birkaç şey daha sunacağım:

a) sözlüğün tüm DEĞERLERİ nasıl döndürülür:

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

b) sözlüğün ANAHTAR İÇERİR olup olmadığını kontrol edin:

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

c) YENİ anahtar, değer çifti sözlüğe nasıl eklenir:

c (foo, tic2 = 44)

Sonuçlar:

tic       tac       toe     tic2
12        22        33        44 

d) GERÇEK SÖZLÜK gereksinimi nasıl yerine getirilir - bu tuşlar TEKRAR EDİLEMEZ (BENZERSİZ ANAHTARLAR) B) ve c) 'yi birleştirmeniz ve böyle bir anahtarın olup olmadığını doğrulayan ve istediğiniz şeyi yapmanız gereken: örneğin, eklemeye izin vermeyin, yenisi eskisinden farklıysa değeri güncelleyin veya bir şekilde anahtarı yeniden oluşturun (örn. benzersiz olması için ona bir miktar sayı ekler)

e) sözlükten ANAHTARLA çifti nasıl SİLİR:

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


"Garip anahtar" gibi boşluklar içeren anahtar ekleyebilir miyim?
user1700890

Ayrıca böyle bir şey çalışmıyor c(foo, tic2=NULL). Etrafta iş var mı?
user1700890

15

Sözlük kullanmanın ilk etapta nedeni performanstır. Görev için adlandırılmış vektörleri ve listeleri kullanabilmeniz doğru olsa da sorun, bunların oldukça yavaş hale gelmesi ve daha fazla veriyle hafızanın aç olmasıdır.

Yine de birçok insanın bilmediği şey, R'nin gerçekten de dahili bir sözlük veri yapısına sahip olmasıdır:hash = TRUE

Nasıl çalıştırılacağını öğrenmek için aşağıdaki örneğe bakın:

# 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

Düzenleme : Bu cevaba dayanarak biraz daha bağlam içeren bir blog yazısı yazdım: http://blog.ephorie.de/hash-me-if-you-can


Çok değerli ilişkiler için çalışıyor mu? Örneğin tic = 1 ve tic = 17
skan

@skan: Neden denemiyorsun?
vonjd

Bu yaklaşımı isimler içeren listeleri kullanmak yerine kullanmak çalışma süremi 6 dakikadan 1 saniyeye düşürdü! Karmaları iyi anlıyorum, ancak herhangi biri bir listede bir isim ararken ne tür bir arama algo kullanıldığını doğrulayabilir mi? Bu sadece eşleşmeler adının altındaki listede yineleme mi yapıyor? Listelerin neden bu kadar yavaş olduğunu ve ayrıca karmaların neden çok sayıda anahtar için bu kadar hızlı olduğunu anlamak istiyorum.
Phil

@vonjd R'de sözlüğü kullanmaya çalışıyorum ve bu uygulamayı buldum. Bununla birlikte, her değer bir çift anahtarla ilişkilendirildiğinde de çalışır mı? Şimdiden teşekkür ederim.
savi

@shana: Tam olarak ne demek istediğine dair bir örnek verebilir misin?
vonjd

9

Paket karması artık kullanılabilir: https://cran.r-project.org/web/packages/hash/hash.pdf

Örnekler

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"

Birden çok değeri nasıl ekleyebilirsiniz? Anahtarı tekrarlamayı denedim ama sadece son değeri saklıyor. Ayrıca listeleri atama denedim ama çalışmıyor
Skan

Sözlükler hiçbir zaman anahtar başına birden fazla değer depolamaz. İsterseniz bir tuşa liste atayabilirsiniz.
BallpointBen

7

Dirk'in cevabının daha kısa varyasyonu:

# 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

Sadece tablebir sözlüğü "taklit etmeye" çalışırken çok fazla yol alabileceğinizi söyleyeceğim , örneğin

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

vb.


as.numeric()Gerekli olduğunu sanmıyorum . Tablo zaten sayısal. Aynı sonucu şununla da elde edebilirsiniznames(t[order(t)])
Rich Scriven
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.