Краткая история. Многие (большинство?) современных языков программирования в широком использовании имеют, по крайней мере, несколько ADT [абстрактных типов данных], в частности,
-
строка (последовательность, состоящая из символов)
-
список (упорядоченный набор значений) и
-
тип на основе карты (неупорядоченный массив, который сопоставляет ключи значениям)
На языке программирования R первые два реализованы как character
и vector
соответственно.
Когда я начал изучать R, две вещи были очевидны почти с самого начала: list
- самый важный тип данных в R (потому что это родительский класс для R data.frame
), а во-вторых, я просто не мог Не понимаю, как они работают, по крайней мере, недостаточно хорошо, чтобы правильно использовать их в моем коде.
Во-первых, мне казалось, что тип данных R list
представляет собой прямую реализацию карты ADT (dictionary
в Python, NSMutableDictionary
в Objective C, hash
в Perl и Ruby, object literal
в Javascript и т.д.).
Например, вы создаете их так же, как и словарь Python, передавая пары ключ-значение конструктору (который в Python dict
not list
):
x = list("ev1"=10, "ev2"=15, "rv"="Group 1")
И вы получаете доступ к элементам R-списка так же, как и словам 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
и типами отображения на других языках в широком использовании (например, Python, Perl, JavaScript):
во-первых, list
в R - упорядоченный набор, точно так же, как и векторы, даже если значения вводятся ключом (т.е. ключи могут быть любым хешируемым значением, а не только целыми целыми числами). Почти всегда тип данных сопоставления на других языках неупорядочен.
second, list
может быть возвращен из функций, даже если вы никогда не передавали в list
при вызове функции, и даже если функция, которая вернула list
, не содержит (явного) list
constructor (Конечно, вы можете справиться с этим на практике, обернув возвращаемый результат при вызове 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
s: кажется, что они не могут быть членами другого 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
к вектору w/к вызову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, я могу, конечно, рекомендовать этот пакет.)