Краткая предыстория: Многие (большинство?) Современные языки программирования в широком распространении имеют по крайней мере несколько общих ADT [абстрактных типов данных], в частности,
строка (последовательность, состоящая из символов)
список (упорядоченный набор значений) и
основанный на карте тип (неупорядоченный массив, который отображает ключи на значения)
В языке программирования R первые два реализованы как character
и vector
, соответственно.
Когда я начал изучать R, две вещи были очевидны почти с самого начала: list
это самый важный тип данных в R (потому что это родительский класс для R data.frame
), а во-вторых, я просто не мог понять, как они работали, по крайней мере, недостаточно хорошо, чтобы правильно использовать их в моем коде.
Во-первых, мне показалось, что list
тип данных R является простой реализацией карты ADT ( dictionary
в Python, NSMutableDictionary
в Objective C, hash
в Perl и Ruby, object literal
в Javascript и т. Д.).
Например, вы создаете их так же, как словарь Python, передавая пары ключ-значение в конструктор (чего в Python dict
нет list
):
x = list("ev1"=10, "ev2"=15, "rv"="Group 1")
И вы получаете доступ к элементам R List точно так же, как и к словарю Python, например x['ev1']
. Аналогично, вы можете получить только «ключи» или только «значения» :
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
но R list
также не похожи на другие ADT типа карты (из всех языков, которые я изучал в любом случае). Я предполагаю, что это является следствием начальной спецификации для S, то есть намерения разработать DSL для данных / статистики с нуля с нуля.
три существенных различия между R list
s и типами отображения в других языках в широком распространении (например, Python, Perl, JavaScript):
list
Во- первых , s в R - это упорядоченная коллекция, как и векторы, даже если значения имеют ключи (т. е. ключи могут быть любыми хешируемыми значениями, а не только последовательными целыми числами). Почти всегда тип данных отображения в других языках неупорядочен .
во-вторых , list
s могут быть возвращены из функций, даже если вы никогда не передавали в них, list
когда вызывали функцию, и даже если функция, которая возвратила list
, не содержит (явного) list
конструктора (Конечно, вы можете справиться с этим на практике, завершение возвращенного результата в вызове 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
Третья особенность R - х list
лет: это не кажется , что они могут быть членами другого ADT, и если вы попытаетесь сделать это , то первичный контейнер принуждают к list
. Например,
x = c(0.5, 0.8, 0.23, list(0.5, 0.2, 0.9), recursive=TRUE)
class(x)
# [1] list
мое намерение здесь не в том, чтобы критиковать язык или как он задокументирован; аналогично, я не предполагаю, что что-то не так со list
структурой данных или их поведением. Все, что мне нужно, это исправить, это мое понимание того, как они работают, чтобы я мог правильно использовать их в своем коде.
Вот те вещи, которые я хотел бы лучше понять:
Какие правила определяют, когда вызов функции возвратит
list
(например,strsplit
выражение, приведенное выше)?Если я не назначаю имена явно
list
(например,list(10,20,30,40)
), имена по умолчанию - это просто последовательные целые числа, начинающиеся с 1? (Я предполагаю, но я далеко не уверен, что ответ - да, иначе мы не смогли бы привести этот типlist
к вектору с вызовомunlist
.)Почему эти два разных оператора
[]
, и[[]]
, возвращают один и тот же результат?x = list(1, 2, 3, 4)
оба выражения возвращают «1»:
x[1]
x[[1]]
почему эти два выражения не возвращают одинаковый результат?
x = list(1, 2, 3, 4)
x2 = list(1:4)
Пожалуйста, не указывайте мне на Документацию R ( ?list
, R-intro
) - я внимательно ее прочитал, и она не помогает мне ответить на тип вопросов, которые я изложил чуть выше.
(наконец, я недавно узнал и начал использовать пакет R (доступный в CRAN), hash
который реализует обычное поведение типа карты через класс S4; я, безусловно, могу рекомендовать этот пакет.)
list
в R не похожи на хэш. У меня есть еще один, который я считаю достойным внимания. list
в R может быть два члена с одинаковыми ссылочными именами. Считайте, что obj <- c(list(a=1),list(a=2))
это допустимо и возвращает список с двумя именованными значениями 'a'. В этом случае вызов for obj["a"]
вернет только первый соответствующий элемент списка. Вы можете получить поведение, подобное (может быть, идентичное) хешу только с одним элементом на x <- new.env(); x[["a"]] <- 1; x[["a"]] <- 2; x[["a"]]
x = list(1, 2, 3, 4)
оба они НЕ возвращают один и тот же результат:,x[1]
иx[[1]]
. Первый возвращает список, а второй возвращает числовой вектор. Прокручивая ниже, мне кажется, что Дирк был единственным респондентом, который правильно ответил на этот вопрос.