2012-03-12 35 views
13

Tôi gặp phải một hành vi lạ trong R với chức năng sapply(). Hàm này được cho là trả về một vectơ, nhưng trong trường hợp đặc biệt, nơi bạn cho nó một vectơ trống, nó trả về một danh sách.Tại sao sapply() trả lại một danh sách?

hành vi đúng với một vector:

a = c("A", "B", "C") 
a[a == "B"] # Returns "B" 
a[sapply(a, function(x) {x == "B"})] # Returns "B" 

hành vi đúng với giá trị NULL:

a = NULL 
a[a == "B"] # Returns NULL 
a[sapply(a, function(x) {x == "B"})] # Returns NULL 

hành vi kỳ lạ với một vector rỗng:

a = vector() 
a[a == "B"] # Returns NULL 
a[sapply(a, function(x) {x == "B"})] # Erreur : type 'list' d'indice incorrect 

Cùng thông báo lỗi như với tuyên bố này:

a[list()] # Erreur dans a[list()] : type 'list' d'indice incorrect 

Tại sao? Nó là một lỗi?

Do hành vi lạ này, tôi sử dụng unlist(lapply()).

+4

Protip- nó không bao giờ là lỗi –

+2

@ChrisBeeley - Không bao giờ là lỗi, luôn luôn là "tính năng" ;-) R (và S) có một loạt các tính năng "ít" lý tưởng mặc dù, và đây là một trong số chúng . '1: 0' là một ... – Tommy

Trả lời

17

Lý do thực sự cho việc này là sapply không biết chức năng của bạn sẽ trở lại mà không cần gọi. Trong trường hợp của bạn, hàm trả về một số logical, nhưng vì sapply được cung cấp một danh sách trống, hàm này không bao giờ được gọi. Vì vậy, nó phải đưa ra một loại và nó mặc định là list.

... Vì lý do này (và cho hiệu suất), vapply đã được giới thiệu! Nó yêu cầu bạn chỉ định kiểu giá trị trả về (và chiều dài). Điều này cho phép nó làm điều đúng. Là tiền thưởng, nó cũng nhanh hơn!

sapply(LETTERS[1:3], function(x) {x == "B"}) # F, T, F 
sapply(LETTERS[0], function(x) {x == "B"}) # list() 

vapply(LETTERS[1:3], function(x) {x == "B"}, logical(1)) # F, T, F 
vapply(LETTERS[0], function(x) {x == "B"}, logical(1)) # logical() 

Xem ?vapply để biết thêm thông tin.

2

Thực ra, cả hai đều trả về list. Sự khác biệt duy nhất giữa hai là khi bạn cố gắng chỉ mục NULL nó luôn trả về NULL (ngay cả khi chỉ mục của bạn là một danh sách), nhưng khi bạn cố gắng lập chỉ mục một vectơ trống, nó sẽ kiểm tra chỉ mục và nhận ra nó là list.

a = NULL 
res = sapply(a, function(x) x == "B") # Res is an empty list 
a[res] # returns NULL, because any index of NULL is NULL. 


a = vector() 
res = sapply(a, function(x) x == "B") # Still an empty list. 
a[res] # but you can't index a vector with a list! 
6

Sự giúp đỡ cho hàm ?sapply có này trong Value phần

For ‘sapply(simplify = TRUE)’ and ‘replicate(simplify = TRUE)’: if 
‘X’ has length zero or ‘n = 0’, an empty list. 

Trong cả hai trường hợp của bạn:

> length(NULL) 
[1] 0 
> length(vector()) 
[1] 0 

Do đó sapply() lợi nhuận:

> sapply(vector(), function(x) {x == "B"}) 
list() 
> sapply(NULL, function(x) {x == "B"}) 
list() 

lỗi của bạn không phải là từ sapply() nhưng từ [ vì điều này cho thấy:

> a[list()] 
Error in a[list()] : invalid subscript type 'list' 

Vì vậy, vấn đề này liên quan đến cách Subsetting của NULL và một vector rỗng (vector()) được thực hiện. Không có gì để làm với sapply() cả. Trong cả hai trường hợp, nó trả về đầu ra nhất quán, một danh sách trống.

Các vấn đề liên quan