Breve background: molti (la maggior parte?) Linguaggi di programmazione contemporanei in uso diffuso hanno almeno una manciata di ADT [tipi di dati astratti] in comune, in particolare,
stringa (una sequenza composta da caratteri)
list (una raccolta ordinata di valori) e
tipo basato su mappa (un array non ordinato che associa le chiavi ai valori)
Nel linguaggio di programmazione R, i primi due sono implementati come character
e vector
, rispettivamente.
Quando ho iniziato a studiare R, due cose erano ovvie quasi dall'inizio: list
è il tipo di dati più importante in R (perché è la classe genitore per la R data.frame
), e in secondo luogo, non riuscivo a capire come funzionavano, almeno non abbastanza bene da usarli correttamente nel mio codice.
Per prima cosa, mi è sembrato che il list
tipo di dati di R fosse un'implementazione diretta della mappa ADT ( dictionary
in Python, NSMutableDictionary
in Obiettivo C, hash
in Perl e Ruby, object literal
in Javascript e così via).
Ad esempio, li crei proprio come faresti con un dizionario Python, passando coppie chiave-valore a un costruttore (cosa che in Python dict
non lo è list
):
x = list("ev1"=10, "ev2"=15, "rv"="Group 1")
E accedi agli elementi di un Elenco R proprio come faresti con quelli di un dizionario Python, ad es x['ev1']
. Allo stesso modo, puoi recuperare solo le "chiavi" o solo i "valori" :
names(x) # fetch just the 'keys' of an R list
# [1] "ev1" "ev2" "rv"
unlist(x) # fetch just the 'values' of an R list
# ev1 ev2 rv
# "10" "15" "Group 1"
x = list("a"=6, "b"=9, "c"=3)
sum(unlist(x))
# [1] 18
ma gli R list
sono anche diversi dagli altri ADT di tipo cartografico (tra le lingue che ho imparato comunque). La mia ipotesi è che questa sia una conseguenza delle specifiche iniziali per S, ovvero l'intenzione di progettare un DSL [linguaggio specifico del dominio] di dati / statistiche da zero.
tre differenze significative tra R list
e tipi di mappatura in altre lingue in uso diffuso (ad es. Python, Perl, JavaScript):
in primo luogo , list
s in R sono una raccolta ordinata , proprio come i vettori, anche se i valori sono codificati (ovvero, le chiavi possono essere qualsiasi valore hash non solo numeri interi sequenziali). Quasi sempre, il tipo di dati di mappatura in altre lingue non è ordinato .
secondo , list
s può essere restituito da funzioni anche se non hai mai passato a list
quando hai chiamato la funzione, e anche se la funzione che ha restituito la list
non contiene un list
costruttore ( esplicito) (Ovviamente, puoi gestirlo in pratica da racchiudendo il risultato restituito in una chiamata a unlist
):
x = strsplit(LETTERS[1:10], "") # passing in an object of type 'character'
class(x) # returns 'list', not a vector of length 2
# [1] list
Una terza caratteristica peculiare di R list
: non sembra che possano essere membri di un altro ADT, e se si tenta di farlo, il contenitore primario viene forzato in a list
. Per esempio,
x = c(0.5, 0.8, 0.23, list(0.5, 0.2, 0.9), recursive=TRUE)
class(x)
# [1] list
la mia intenzione qui non è di criticare la lingua o il modo in cui è documentata; allo stesso modo, non sto suggerendo che ci sia qualcosa di sbagliato nella list
struttura dei dati o nel modo in cui si comporta. Tutto quello che sto cercando di correggere è la mia comprensione di come funzionano in modo da poterli usare correttamente nel mio codice.
Ecco il genere di cose che vorrei capire meglio:
Quali sono le regole che determinano quando una chiamata di funzione restituirà un
list
(es.strsplit
Espressione sopra citata)?Se non assegno esplicitamente nomi a un
list
(ad es.list(10,20,30,40)
) , I nomi predefiniti sono solo numeri interi sequenziali che iniziano con 1? (Presumo, ma non sono certo che la risposta sia sì, altrimenti non saremmo in grado di forzare questo tipo dilist
un vettore con una chiamata aunlist
.)Perché questi due diversi operatori
[]
e[[]]
restituiscono lo stesso risultato?x = list(1, 2, 3, 4)
entrambe le espressioni restituiscono "1":
x[1]
x[[1]]
perché queste due espressioni non restituiscono lo stesso risultato?
x = list(1, 2, 3, 4)
x2 = list(1:4)
Per favore, non indicarmi la Documentazione R ( ?list
, R-intro
): l'ho letto attentamente e non mi aiuta a rispondere al tipo di domande che ho appena esposto.
(infine, di recente ho appreso e iniziato a utilizzare un pacchetto R (disponibile su CRAN) chiamato hash
che implementa il comportamento convenzionale del tipo di mappa tramite una classe S4; posso sicuramente consigliare questo pacchetto.)
list
in R non è come un hash. Ne ho uno in più che ritengo degno di nota. list
in R possono avere due membri con lo stesso nome di riferimento. Considera che obj <- c(list(a=1),list(a=2))
è valido e restituisce un elenco con due valori nominati di 'a'. In questo caso, una chiamata per obj["a"]
restituirà solo il primo elemento dell'elenco corrispondente. Puoi ottenere un comportamento simile (forse identico) a un hash con un solo oggetto per nomi di riferimento usando ambienti in R. es.x <- new.env(); x[["a"]] <- 1; x[["a"]] <- 2; x[["a"]]
x = list(1, 2, 3, 4)
, entrambi questi NON restituiscono lo stesso risultato:,x[1]
ex[[1]]
. Il primo restituisce un elenco e il secondo restituisce un vettore numerico. Scorrendo sotto mi sembra che Dirk sia stato l'unico rispondente a rispondere correttamente a questa domanda.