lapply z funkcją"$"

Powiedzmy, że mam listę danych.ramki

dflist <- list(data.frame(a=1:3), data.frame(b=10:12, a=4:6))

Jeśli chcę wyodrębnić pierwszą kolumnę z każdej pozycji na liście, mogę zrobić

lapply(dflist, `[[`, 1)
# [[1]]
# [1] 1 2 3
# 
# [[2]]
# [1] 10 11 12

Dlaczego nie mogę używać funkcji "$" w ten sam sposób

lapply(dflist, `$`, "a")
# [[1]]
# NULL
# 
# [[2]]
# NULL

Ale oba działają:

lapply(dflist, function(x) x$a)
`$`(dflist[[1]], "a")

Zdaję sobie sprawę, że w tym przypadku można użyć

lapply(dflist, `[[`, "a")

Ale pracowałem z obiektem S4, który nie pozwalał na indeksowanie przez [[. Na przykład

library(adegenet)
data(nancycats)
catpop <- genind2genpop(nancycats)
mylist <- list(catpop, catpop)

#works
catpop[[1]]$tab

#doesn't work
lapply(mylist, "$", "tab")
# Error in slot(x, name) : 
#   no slot of name "..." for this object of class "genpop"

#doesn't work
lapply(mylist, "[[", "tab")
# Error in FUN(X[[1L]], ...) : this S4 class is not subsettable
 35
Author: MrFlick, 2015-05-08

2 answers

Dla pierwszego przykładu, można po prostu zrobić:

lapply(dflist, `$.data.frame`, "a")

Dla drugiej, użyj slot() funkcji accessor

lapply(mylist, "slot", "tab")

Nie jestem pewien Dlaczego metoda dispatch nie działa w pierwszym przypadku, ale Note sekcja ?lapply rozwiązuje ten sam problem swojej metody borked dispatch dla prymitywnych funkcji, takich jak $:

 Note:

 [...]

 For historical reasons, the calls created by ‘lapply’ are
 unevaluated, and code has been written (e.g., ‘bquote’) that
 relies on this.  This means that the recorded call is always of
 the form ‘FUN(X[[i]], ...)’, with ‘i’ replaced by the current
 (integer or double) index.  This is not normally a problem, but it
 can be if ‘FUN’ uses ‘sys.call’ or ‘match.call’ or if it is a
 primitive function that makes use of the call.  This means that it
 is often safer to call primitive functions with a wrapper, so that
 e.g. ‘lapply(ll, function(x) is.numeric(x))’ is required to ensure
 that method dispatch for ‘is.numeric’ occurs correctly.
 27
Author: Josh O'Brien,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-08 20:22:28

Wydaje się więc, że ten problem ma więcej wspólnego z $ i tym, jak zwykle oczekuje nienotowanych nazw jako drugiego parametru, a nie łańcuchów. Spójrz na ten przykład

dflist <- list(
    data.frame(a=1:3, z=31:33), 
    data.frame(b=10:12, a=4:6, z=31:33)
)
lapply(dflist, 
    function(x, z) {
        print(paste("z:",z)); 
        `$`(x,z)
    }, 
    z="a"
)

Widzimy wyniki

[1] "z: a"
[1] "z: a"
[[1]]
[1] 31 32 33

[[2]]
[1] 31 32 33

Więc z wartość jest ustawiana na "a", ale $ nie ocenia drugiego parametru. Więc zwraca kolumnę " z "zamiast kolumny" a". Prowadzi to do tego interesującego zestawu wyników

a<-"z"; `$`(dflist[[1]], a)
# [1] 1 2 3
a<-"z"; `$`(dflist[[1]], "z")
# [1] 31 32 33

a<-"z"; `$.data.frame`(dflist[[1]], a)
# [1] 31 32 33
a<-"z"; `$.data.frame`(dflist[[1]], "z")
# [1] 31 32 33

Kiedy wywołujemy $.data.frame bezpośrednio omijamy standardowe odejście, które występuje w prymitywnym przed wysyłaniem (co dzieje się w pobliżu tutaj w źródle).

Dodany haczyk z {[10] } polega na tym, że przekazuje on argumenty do funkcji za pośrednictwem mechanizmu .... Na przykład

lapply(dflist, function(x, z) sys.call())
# [[1]]
# FUN(X[[2L]], ...)

# [[2]]
# FUN(X[[2L]], ...)

Oznacza to, że gdy wywoływane jest $, odchodzi ... do łańcucha "...". To wyjaśnia to zachowanie

dflist<- list(data.frame(a=1:3, "..."=11:13, check.names=F))
lapply(dflist, `$`, "a")
# [[1]]
# [1] 11 12 13

To samo dzieje się, gdy próbujesz użyć ... siebie

f<-function(x,...) `$`(x, ...); 

f(dflist[[1]], "a");
# [1] 11 12 13
`$`(dflist[[1]], "a")
# [1] 1 2 3
 12
Author: MrFlick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-08 21:25:30