У меня есть следующий список

test_list=list(list(a=1,b=2),list(a=3,b=4))

И я хочу извлечь все элементы с именем элемента списка a.

Я могу сделать это через

sapply(test_list,`[[`,"a")

Что дает мне правильный результат

#[1] 1 3

Когда я пробую то же самое с оператором доллара рупий $, я получаю NULL

sapply(test_list,`$`,"a")
#[[1]]
#NULL
#
#[[2]]
#NULL

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

`$`(test_list[[1]],"a")
#[1] 1

Я упустил что-то очевидное?

13
cryo111 31 Дек 2015 в 13:21

2 ответа

Лучший ответ

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

Во-первых, сопоставляется второй элемент $, но не оценивается, поэтому он не может быть переменной.

Во-вторых, когда аргументы передаются функциям, они присваиваются соответствующим переменным в вызове функции. При передаче в sapply "a" присваивается переменной и поэтому больше не будет работать с $. Мы можем увидеть это, запустив

sapply("a", print)
[1] "a"
  a 
"a"

Это может привести к таким странным результатам

sapply(test_list, function(x, a) {`$`(x, a)})
[1] 1 3

Где, несмотря на то, что a является переменной (которая даже не была назначена), $ сопоставляет ее с именами элементов в списке.

6
Community 23 Май 2017 в 11:44

оценка по сравнению с отсутствием

[[ оценивает свой аргумент, а $ - нет. L[[a]] получает компонент L, имя которого хранится в переменной a. $ просто передает само имя аргумента в виде строки символов, поэтому L$a находит компонент "a" для L. a не рассматривается как переменная, содержащая имя компонента - это просто строка символов.

Ниже L[[b]] возвращает компонент L с именем "a", потому что переменная b имеет значение "a", тогда как L$b возвращает компонент {{X6 }} с именем "b", потому что с этим синтаксисом b не рассматривается как переменная, а рассматривается как строка символов, которая сама передается.

L <- list(a = 1, b = 2)
b <- "a"
L[[b]] # same as L[["a"]] since b holds a
## [1] 1
L$b  # same as L[["b"]] since b is regarded as a character string to be passed
## [1] 2

саппли

Теперь, когда мы понимаем ключевое различие между $ и [[, чтобы увидеть, что происходит с sapply, рассмотрим этот пример. Мы превратили каждый элемент test_list в объект "foo" и определили наши собственные методы $.foo и [[.foo, которые просто показывают, что R передает методу через {{X5 }} аргумент:

foo_list <- test_list
class(foo_list[[1]]) <- class(foo_list[[2]]) <- "foo"

"$.foo" <- "[[.foo" <- function(x, name) print(name)

result <- sapply(foo_list, "$", "a")
## "..."
## "..."

result2 <- sapply(foo_list, "[[", "a")    
## [1] "a"
## [1] "a"

В первом случае происходит то, что sapply вызывает whatever$..., а ... не оценивается, поэтому он будет искать компонент списка, который буквально назван "..." и, конечно, такого компонента нет, поэтому whatever$... имеет значение NULL, следовательно, значения NULL показаны в выводе в вопросе. Во втором случае whatever[[[...]] оценивается как whatever[["a"]], отсюда и наблюдаемый результат.

11
G. Grothendieck 31 Дек 2015 в 14:44