Краткая история. Многие (большинство?) современных языков программирования в широком использовании имеют, по крайней мере, несколько 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, я могу, конечно, рекомендовать этот пакет.)