Ответ 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