Breve reseña: Muchos (¿la mayoría?) Lenguajes de programación contemporáneos de uso generalizado tienen al menos un puñado de ADT [tipos de datos abstractos] en común, en particular,
cadena (una secuencia compuesta de caracteres)
lista (una colección ordenada de valores) y
tipo basado en mapas (una matriz desordenada que asigna claves a valores)
En el lenguaje de programación R, los dos primeros se implementan como character
y vector
, respectivamente.
Cuando comencé a aprender R, dos cosas eran obvias casi desde el principio: list
es el tipo de datos más importante en R (porque es la clase principal para R data.frame
), y en segundo lugar, simplemente no podía entender cómo funcionaban, al menos no lo suficientemente bien como para usarlos correctamente en mi código.
Por un lado, me pareció que el list
tipo de datos de R era una implementación directa del mapa ADT ( dictionary
en Python, NSMutableDictionary
en el Objetivo C, hash
en Perl y Ruby, object literal
en Javascript, etc.).
Por ejemplo, los crea como si fuera un diccionario de Python, pasando pares clave-valor a un constructor (que en Python dict
no lo es list
):
x = list("ev1"=10, "ev2"=15, "rv"="Group 1")
Y se accede a los elementos de una lista de R al igual que lo haría con las de un diccionario de Python, por ejemplo, x['ev1']
. Del mismo modo, puede recuperar solo las 'claves' o solo los 'valores' al:
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
pero los R list
también son diferentes a otros ADT de tipo mapa (de todos los idiomas que he aprendido de todos modos). Mi conjetura es que esto es una consecuencia de la especificación inicial para S, es decir, una intención de diseñar un DSL de datos / estadísticas [lenguaje específico de dominio] desde cero.
tres diferencias significativas entre R list
sy tipos de mapeo en otros idiomas en uso generalizado (p. ej., Python, Perl, JavaScript):
primero , list
s en R son una colección ordenada , al igual que los vectores, a pesar de que los valores están codificados (es decir, las claves pueden ser cualquier valor hashable no solo enteros secuenciales). Casi siempre, el tipo de datos de mapeo en otros idiomas no está ordenado .
segundo , list
s puede ser devuelto desde funciones aunque nunca haya pasado a list
cuando llamó a la función, y aunque la función que devolvió el list
no contiene un list
constructor ( explícito) (Por supuesto, puede tratar esto en la práctica mediante envolviendo el resultado devuelto en una llamada 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 tercera característica peculiar de las R list
: no parece que puedan ser miembros de otro ADT, y si intenta hacerlo, el contenedor primario se convierte en a list
. P.ej,
x = c(0.5, 0.8, 0.23, list(0.5, 0.2, 0.9), recursive=TRUE)
class(x)
# [1] list
mi intención aquí no es criticar el lenguaje o cómo está documentado; Del mismo modo, no estoy sugiriendo que haya algo mal con la list
estructura de datos o cómo se comporta. Todo lo que busco es corregir mi comprensión de cómo funcionan para poder usarlos correctamente en mi código.
Estas son las cosas que me gustaría entender mejor:
¿Cuáles son las reglas que determinan cuándo una llamada de función devolverá un
list
(p. Ej.,strsplit
Expresión mencionada anteriormente)?Si no asigno explícitamente nombres a
list
(p. Ej.list(10,20,30,40)
) , ¿ Son los nombres predeterminados solo enteros secuenciales que comienzan con 1? (Asumo, pero no estoy seguro de que la respuesta sea sí, de lo contrario no podríamos obligar a este tipolist
a un vector con una llamada aunlist
).¿Por qué estos dos operadores diferentes
[]
, y[[]]
, devuelven el mismo resultado?x = list(1, 2, 3, 4)
ambas expresiones devuelven "1":
x[1]
x[[1]]
¿Por qué estas dos expresiones no devuelven el mismo resultado?
x = list(1, 2, 3, 4)
x2 = list(1:4)
Por favor, no me señale la Documentación R ( ?list
, R-intro
): la he leído detenidamente y no me ayuda a responder el tipo de preguntas que recité anteriormente.
(por último, recientemente me enteré y comencé a usar un paquete R (disponible en CRAN) llamado hash
que implementa el comportamiento de tipo de mapa convencional a través de una clase S4; ciertamente puedo recomendar este paquete).
list
en que R no es como un hash. Tengo uno más que creo que es digno de mención. list
en R puede tener dos miembros con el mismo nombre de referencia. Considere que obj <- c(list(a=1),list(a=2))
es válido y devuelve una lista con dos valores con nombre de 'a'. En este caso, una solicitud obj["a"]
solo devolverá el primer elemento de la lista coincidente. Puede obtener un comportamiento similar (tal vez idéntico) a un hash con solo un elemento por cada nombre de referencia utilizando entornos en R. ej .x <- new.env(); x[["a"]] <- 1; x[["a"]] <- 2; x[["a"]]
x = list(1, 2, 3, 4)
, ambos NO devuelven el mismo resultado:x[1]
yx[[1]]
. El primero devuelve una lista y el segundo devuelve un vector numérico. Al desplazarme a continuación, me parece que Dirk fue el único encuestado que respondió esta pregunta correctamente.