Như đã được ghi nhận, vapply
thực hiện hai điều:
- cải thiện tốc độ nhẹ
- Cải thiện tính nhất quán bằng cách cung cấp kiểm tra kiểu trả về hạn chế.
Điểm thứ hai là lợi thế lớn hơn, vì nó giúp bắt lỗi trước khi chúng xảy ra và dẫn đến mã mạnh hơn. Việc kiểm tra giá trị trả lại này có thể được thực hiện riêng bằng cách sử dụng sapply
theo sau là stopifnot
để đảm bảo rằng giá trị trả về phù hợp với những gì bạn mong đợi, nhưng vapply
thì dễ dàng hơn một chút (nếu bị giới hạn hơn, vì mã kiểm tra lỗi tùy chỉnh có thể kiểm tra các giá trị trong giới hạn , v.v.)
Dưới đây là ví dụ về số vapply
đảm bảo kết quả của bạn như mong đợi. Điều này tương tự với điều tôi đang làm trong khi đang cạo PDF, trong đó findD
sẽ sử dụng regex để khớp mẫu trong dữ liệu thô (ví dụ: tôi có danh sách là split
theo thực thể và regex để khớp với địa chỉ trong mỗi thực thể. Thỉnh thoảng, PDF đã được chuyển đổi không đúng thứ tự và sẽ có hai địa chỉ cho một thực thể, điều này gây ra sự xấu).
> input1 <- list(letters[1:5], letters[3:12], letters[c(5,2,4,7,1)])
> input2 <- list(letters[1:5], letters[3:12], letters[c(2,5,4,7,15,4)])
> findD <- function(x) x[x=="d"]
> sapply(input1, findD)
[1] "d" "d" "d"
> sapply(input2, findD)
[[1]]
[1] "d"
[[2]]
[1] "d"
[[3]]
[1] "d" "d"
> vapply(input1, findD, "")
[1] "d" "d" "d"
> vapply(input2, findD, "")
Error in vapply(input2, findD, "") : values must be length 1,
but FUN(X[[3]]) result is length 2
Khi tôi nói với sinh viên, một phần trở thành lập trình viên đang thay đổi suy nghĩ của bạn từ "lỗi gây khó chịu" thành "lỗi là bạn của tôi".
Zero, chiều dài đầu vào
Một điểm liên quan là nếu độ dài đầu vào là zero, sapply
sẽ luôn trả về một danh sách rỗng, không phụ thuộc vào loại đầu vào. Hãy so sánh:
sapply(1:5, identity)
## [1] 1 2 3 4 5
sapply(integer(), identity)
## list()
vapply(1:5, identity)
## [1] 1 2 3 4 5
vapply(integer(), identity)
## integer(0)
Với vapply
, bạn được đảm bảo để có một loại đặc biệt của đầu ra, do đó bạn không cần phải viết kiểm tra thêm cho zero đầu vào chiều dài.
Benchmarks
vapply
có thể nhanh hơn một chút vì nó đã biết những gì định dạng nó nên được mong đợi các kết quả trong.
input1.long <- rep(input1,10000)
library(microbenchmark)
m <- microbenchmark(
sapply(input1.long, findD),
vapply(input1.long, findD, "")
)
library(ggplot2)
library(taRifx) # autoplot.microbenchmark is moving to the microbenchmark package in the next release so this should be unnecessary soon
autoplot(m)
Có thể dự đoán được nhiều hơn, làm cho mã ít mơ hồ hơn và mạnh mẽ hơn. Đặc biệt trong các dự án lớn hơn, nói một gói lớn, điều này là có liên quan. –
Không cần “P.S.”… chỉ cần tự trả lời câu hỏi. –
@KonradRudolph Đôi khi các lưu ý về hiệu ứng đó có thể tập trung vào câu hỏi và tránh các câu trả lời "RTFM". :-) –