В чем разница между списком и парным списком в R?

При чтении документации для списков я нашел ссылки на парные списки, но мне было непонятно, как они отличаются от списков.

Ответы

Ответ 1

Пайперы изо дня в день R

Есть два места, в которых парные списки будут отображаться обычно в день за днем ​​R. Один из них является форматом функции:

str(formals(var))

Другое - это языковые объекты. Например:

quote(1 + 1)

создает список типов языка типов (LANGSXP внутри). Основная причина, по которой вам было бы интересно узнать об этом, это то, что операции, такие как length(<language object>) или language_object[[x]], могут быть медленными из-за того, что парни хранятся внутри (хотя длинные языковые объекты с партией несколько редки, но выражения для заметок не являются параличами).

Обратите внимание, что пустые элементы - это только символы с нулевой длиной, и вы можете хранить их в списках, если вы немного обманываете (хотя вы, вероятно, не должны этого делать):

list(x=substitute(x, alist(x=)))  # hack alert

Все, что говорит, по большей части, OP правильно, что вам не нужно слишком беспокоиться о парных списках, если вы не пишете код C для использования в R.

Внутренние различия между списками и парами

Пары и список отличаются главным образом в структуре хранения. Паралисты хранятся как цепочка узлов, где каждый node указывает на расположение следующего node в дополнение к содержимому node и node "name" (см. статья wiki для CAR/CDR для общего обсуждения). Среди прочего это означает, что вы не можете знать, сколько элементов в парном списке, если вы не знаете, какой элемент является первым, и затем переходите весь список.

Pairlists широко используются в R-компонентах и ​​существуют при обычном использовании R, но большую часть времени маскируются методами печати или доступа и/или принуждаются к спискам при доступе.

Списки также представляют собой список адресов, но в отличие от парных списков все адреса хранятся в одной смежной ячейке памяти, а общая длина отслеживается. Это упрощает доступ к любому произвольному члену списка по местоположению, поскольку вы можете просто искать адрес в таблице памяти. С парным списком вам придется перейти с node на node, пока вы не дойдете до нужного node. Имена также сохраняются как атрибуты самого списка, а не привязаны к каждому node парного списка.

Преимущества парных списков

Одно (как правило, небольшое) преимущество парных списков заключается в том, что вы можете добавить к ним минимальные накладные расходы, так как вам нужно изменить не более двух узлов (node впереди нового node и самого нового node), тогда как со списком вам может потребоваться перераспределить всю таблицу адресов с увеличением размера (обычно это не большая проблема, поскольку таблица адресов обычно очень мала по сравнению с размером данных, на которые указывает таблица). Существует также множество алгоритмов, которые специализируются на манипулировании парными списками (например, сортировка, индексирование и т.д.), Но они также могут быть перенесены в обычные списки.

Менее актуальным для повседневного использования, поскольку вы можете делать это только внутри, очень легко изменить список с точки зрения программирования, изменив то, что указывает любой произвольный элемент.

Несравненно связанный с вышеперечисленным, парные списки, вероятно, будут более эффективными, если у вас есть сильно вложенные объекты. списки могут легко реплицировать эту структуру, но каждый список и вложенный список будут привязаны к дополнительной таблице адресов памяти. Вероятно, это связано с тем, что для языковых объектов, которые, как правило, имеют высокий коэффициент вложенности/элементов, используются парные списки.

Подробнее см. R Internals (найдите LISTSXP и VECSXP, парные списки и списки соответственно, в связанной местоположение).

edit: интересно эксперимент по сравнению с памятью списка списка с парным списком показывает, что парный список больше, поэтому аргумент эффективности хранения может быть неправильным (не уверен, что здесь можно доверять object.size):

> plist_to_list <- function(x) {
+   if(is.call(x)) x <- as.list(x)
+   if(length(x) > 1) for(i in 2:length(x)) x[[i]] <- Recall(x[[i]])
+   x
+ }
> add_quote <- function(x, y) call("+", x, y)
> x <- Reduce(add_quote, lapply(letters, as.name))
> object.size(x)
7056 bytes
> y <- plist_to_list(x)
> object.size(y)
4656 bytes

Ответ 2

Прежде всего, парные списки устарели

парные списки устарели для нормального использования. Вам никогда не придется беспокоиться о них, если вы не работаете с внутренними сотрудниками R.


списки могут содержать именованные элементы

Каждый элемент в списке из R может иметь имя. Вы можете получить доступ к каждому элементу в списке либо по имени, либо по его числовому индексу.

Вот пример списка, в котором второй элемент имеет имя 'second':

> my.list <- list('A',second='B','C')
> my.list
[[1]]
[1] "A"

$second
[1] "B"

[[3]]
[1] "C"

Все элементы могут быть проиндексированы по своей позиции в списке. К именованным элементам можно дополнительно обращаться по имени:

> my.list[[2]]
[1] "B"
> my.list$second
[1] "B"

Кроме того, каждый элемент в списке является вектором, даже если он является только вектором, содержащим один элемент. Подробнее о списках см. Как правильно использовать списки в R?.


парные списки могут содержать пустые именованные элементы

Пакет-список в основном совпадает с списком, за исключением того, что парный список может содержать пустой именованный элемент, но список не может. Кроме того, парный список создается с использованием функции alist.

> list('A',second=,'C')
Error in as.pairlist(list(...)) : argument is missing, with no default
> alist('A',second=,'C')
[[1]]
[1] "A"

$second


[[3]]
[1] "C"

Но, как упоминалось ранее, они устарели. Они не имеют никакой пользы или преимущества над списками, о которых я знаю.