Arbeiten mit Wörterbüchern / Listen in R.

89

Ich habe eine triviale Frage: Ich konnte keine Wörterbuchdatenstruktur in R finden, also habe ich stattdessen Liste verwendet (wie "Wort" -> Nummer). Im Moment habe ich also Probleme, wie ich die Liste der Schlüssel erhalte. Weiß jemand Bescheid?

Ivri
quelle

Antworten:

118

Ja, der listTyp ist eine gute Annäherung. Sie können names()in Ihrer Liste verwenden, um die 'Schlüssel' festzulegen und abzurufen:

> 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
quelle
17
+1 für die Beantwortung einer Frage ohne ein Wort über den ineffektiven Ansatz von OP.
Marek
3
Abhängig von der beabsichtigten Verwendung einer Liste als Proxy für ein Wörterbuch kann es ratsam sein, zu berücksichtigen, dass die "Schlüssel" -Suche für Listen O (n) und nicht O (1) ist, was Sie erwarten würden ein Wörterbuch (das Schlüssel hascht).
Egnha
4
Ja, der environmentTyp wird dafür in R verwendet, ist aber weniger verbreitet / weniger bekannt.
Dirk Eddelbuettel
55

Sie benötigen nicht einmal Listen, wenn Ihre "Zahlen" -Werte alle den gleichen Modus haben. Wenn ich das Beispiel von Dirk Eddelbuettel nehme:

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

Listen sind nur erforderlich, wenn Ihre Werte entweder im gemischten Modus (z. B. Zeichen und Zahlen) oder in Vektoren vorliegen.

Sowohl für Listen als auch für Vektoren kann ein einzelnes Element nach Namen unterteilt werden:

> foo["tac"]
tac 
 22 

Oder für eine Liste:

> foo[["tac"]]
[1] 22
Calimo
quelle
1
Wie können Sie die Liste c(12,22,33)dieser wörterbuchartigen R-Struktur foo erhalten? unlist(lapply(FUN=function(a){foo[[a]]},X = 1:length(foo)))ist sehr unpraktisch. Irgendeine fertige Funktion dafür? Verschob die Frage hierher
hhh
18

Um die Antwort von Calimo ein wenig zu erweitern, präsentiere ich einige weitere Dinge, die Sie beim Erstellen dieser Quasi-Wörterbücher in R nützlich finden können:

a) wie man alle WERTE des Wörterbuchs zurückgibt:

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

b) Überprüfen Sie, ob das Wörterbuch einen Schlüssel enthält:

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

c) Hinzufügen eines neuen Schlüssels und eines Wertpaars zum Wörterbuch:

c (foo, tic2 = 44)

Ergebnisse:

tic       tac       toe     tic2
12        22        33        44 

d) Wie kann die Anforderung von REAL DICTIONARY erfüllt werden - dass Schlüssel NICHT wiederholt werden können (EINZIGARTIGE SCHLÜSSEL)? Sie müssen b) und c) kombinieren und eine Funktion erstellen, die überprüft, ob ein solcher Schlüssel vorhanden ist, und das tun, was Sie möchten: z. B. Einfügen nicht zulassen, Wert aktualisieren, wenn der neue vom alten abweicht, oder Schlüssel irgendwie neu erstellen (z fügt eine Nummer hinzu, damit es eindeutig ist)

e) wie man ein Paar nach Schlüssel aus dem Wörterbuch löscht:

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

Andilabs
quelle
Kann ich einen Schlüssel hinzufügen, der Leerzeichen enthält, so etwas wie einen "seltsamen Schlüssel"?
user1700890
Auch so etwas funktioniert nicht c(foo, tic2=NULL). Irgendeine Arbeit herum?
user1700890
15

Der Grund für die Verwendung von Wörterbüchern ist in erster Linie die Leistung. Obwohl es richtig ist, dass Sie benannte Vektoren und Listen für die Aufgabe verwenden können, besteht das Problem darin, dass sie mit mehr Daten ziemlich langsam und speicherhungrig werden.

Was viele Menschen jedoch nicht wissen, ist, dass R tatsächlich eine eingebaute Wörterbuchdatenstruktur hat: Umgebungen mit der Optionhash = TRUE

Im folgenden Beispiel erfahren Sie, wie es funktioniert:

# 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

Bearbeiten : Auf der Grundlage dieser Antwort habe ich einen Blog-Beitrag mit etwas mehr Kontext geschrieben: http://blog.ephorie.de/hash-me-if-you-can

vonjd
quelle
Funktioniert es für mehrwertige Beziehungen? Zum Beispiel tic = 1 und tic = 17
skan
@skan: Warum probierst du es nicht aus?
vonjd
Die Verwendung dieses Ansatzes anstelle der Verwendung von Listen mit Namen hat meine Laufzeit von 6 Minuten auf 1 Sekunde verkürzt! Ich verstehe Hashes gut, aber kann jemand beim Nachschlagen eines Namens in einer Liste bestätigen, welche Art von Suchalgo verwendet wird? Durchläuft dies nur die Liste unter den Namensübereinstimmungen? Ich möchte genau verstehen, warum Listen so langsam sind und warum Hashes für eine große Anzahl von Schlüsseln so schnell sind.
Phil
@vonjd Ich versuche, das Wörterbuch in R zu verwenden und habe diese Implementierung gefunden. Funktioniert es jedoch auch, wenn jeder Wert einem Schlüsselpaar zugeordnet ist? Vielen Dank im Voraus.
Savi
@shana: Könntest du ein Beispiel geben, was du genau meinst?
vonjd
9

Der Paket- Hash ist jetzt verfügbar: https://cran.r-project.org/web/packages/hash/hash.pdf

Beispiele

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ũ
quelle
Wie können Sie mehrere Werte hinzufügen? Ich habe versucht, den Schlüssel zu wiederholen, aber er speichert nur den letzten Wert. Ich habe auch versucht, Listen
zuzuweisen
Wörterbücher speichern niemals mehrere Werte pro Schlüssel. Sie können einem Schlüssel eine Liste zuweisen, wenn Sie möchten.
BallpointBen
7

Kürzere Variante von Dirks Antwort:

# 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"
Nessel
quelle
4

Ich möchte nur kommentieren, dass Sie eine Menge Kilometer sammeln können, tablewenn Sie versuchen, auch ein Wörterbuch zu "fälschen", z

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

etc.

Gabriel Perdue
quelle
Ich denke nicht, dass as.numeric()es notwendig ist. Die Tabelle ist bereits numerisch. Sie können das gleiche Ergebnis mitnames(t[order(t)])
Rich Scriven