Коротка інформація: Багато (більшість?) Сучасних мов програмування, що широко використовуються, мають принаймні декілька спільних 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, як ви б ті з словника 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
s також не схожі на інші рекламні картки типу (серед мов, яких я навчився в будь-якому випадку). Я здогадуюсь, що це наслідок початкової специфікації для S, тобто наміру створити DSL даних / статистики [мова, що залежить від домену] з нуля.
три суттєві відмінності між list
типами R s та картографуванням в інших мовах при широкому використанні (наприклад, Python, Perl, JavaScript):
по-перше , list
s в R - це впорядкована колекція, подібно до векторів, навіть незважаючи на те, що значення клавішуються (тобто, ключі можуть бути будь-якими хешируемыми значеннями, а не лише послідовними цілими числами). Майже завжди тип даних відображення в інших мовах є не упорядкованим .
по-друге , list
s може бути повернуто з функцій, навіть якщо ви ніколи не переходили в a, 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
структурі даних чи тому, як вона поводиться, щось не так . Я лише хочу виправити своє розуміння того, як вони працюють, щоб я міг правильно використовувати їх у своєму коді.
Ось такі речі, які я хотів би краще зрозуміти:
Які правила визначають, коли виклик функції поверне a
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'. У цьому випадку виклик для obj["a"]
поверне лише перший елемент відповідного списку. Ви можете отримати поведінку, схожу (можливо ідентичну) хешу, лише з одним елементом на x <- new.env(); x[["a"]] <- 1; x[["a"]] <- 2; x[["a"]]
x = list(1, 2, 3, 4)
, обидва вони НЕ повертають однаковий результат:,x[1]
іx[[1]]
. Перший повертає список, а другий повертає числовий вектор. Прокручуючи нижче, мені здається, що Дірк був єдиним респондентом, який правильно вирішив це питання.