2012-06-12 5 views
10

Cho một danh sách a vectơ chứa có độ dài bất bình đẳng và một vector b có chứa một số yếu tố từ các vectơ trong a, tôi muốn có được một vector chiều dài bằng nhau để b chứa chỉ mục trong a nơi phần tử trong b trận (đây là một lời giải thích xấu tôi biết) ...cách nhanh nhận được chỉ số của trận đấu trong danh sách

các mã sau đây không được công việc:

a <- list(1:3, 4:5, 6:9) 
b <- c(2, 3, 5, 8) 

sapply(b, function(x, list) which(unlist(lapply(list, function(y, z) z %in% y, z=x))), list=a) 
[1] 1 1 2 3 

Thay thế sapply với một vòng lặp for đạt được cùng một cours e

Vấn đề là mã này sẽ được sử dụng với danh sách và vectơ có độ dài trên 1000. Trên thực tế, chức năng này mất khoảng 15 giây (cả vòng lặp for và sapply).

Có ai có ý tưởng làm thế nào để tăng tốc độ này, an toàn cho một cách tiếp cận song song không? Tôi đã không nhìn thấy một cách tiếp cận vectorized (và tôi không thể lập trình trong C, mặc dù đó có lẽ sẽ là nhanh nhất).

Edit:

sẽ chỉ nhấn mạnh nhã giải pháp sử dụng trận đấu Aaron() mà đã đưa ra một sự gia tăng tốc độ theo thứ tự của năm 1667 lần (15-0,009)

tôi mở rộng một chút vào nó để cho phép nhiều trận đấu (sự trở lại là sau đó một danh sách)

a <- list(1:3, 3:5, 3:7) 
b <- c(3, 5) 
g <- rep(seq_along(a), sapply(a, length)) 
sapply(b, function(x) g[which(unlist(a) %in% x)]) 
[[1]] 
[1] 1 2 3 

[[2]] 
[1] 2 3 

Thời gian chạy cho điều này là 0,169 mà được cho là khá chậm, nhưng mặt khác linh hoạt hơn

+2

Bạn muốn thuật toán làm gì nếu phần tử 'b' xuất hiện trong nhiều phần tử' a'? Điều đó có thể xảy ra trong vấn đề thực tế của bạn không? –

+0

Tôi nên xác định rằng ... Đó không phải là khả năng – ThomasP85

Trả lời

12

Dưới đây là một khả năng sử dụng match:

> a <- list(1:3, 4:5, 6:9) 
> b <- c(2, 3, 5, 8) 
> g <- rep(seq_along(a), sapply(a, length)) 
> g[match(b, unlist(a))] 
[1] 1 1 2 3 

findInterval là một tùy chọn:

> findInterval(match(b, unlist(a)), cumsum(c(0,sapply(a, length)))+1) 
[1] 1 1 2 3 

Để được trả lại một danh sách, hãy thử này:

a <- list(1:3, 4:5, 5:9) 
b <- c(2,3,5,8,5) 
g <- rep(seq_along(a), sapply(a, length)) 
aa <- unlist(a) 
au <- unique(aa) 
af <- factor(aa, levels=au) 
gg <- split(g, af) 
gg[match(b, au)] 
+0

Từ 15 giây đến 0,009 - đó là một cải tiến ấn tượng. Tôi phát hiện ra rằng tôi thực sự muốn trả lại một danh sách thay vì một vectơ, để nó có thể xử lý nhiều kết quả phù hợp. Tôi thay thế dòng cuối cùng trong đề xuất đầu tiên của bạn với sapply (b, hàm (x) g [trong đó (unlist (a)% in% x)]) để đạt được điều này. Thời gian chạy là 0,169, khá chậm so với thời gian của bạn nhưng vẫn là một cải tiến lớn. – ThomasP85

0

Là một bình luận cho bài viết của bạn gợi ý , nó phụ thuộc vào những gì bạn muốn làm nếu/khi cùng một yếu tố xuất hiện trong nhiều vectơ trong a. Giả sử bạn muốn chỉ số thấp nhất bạn có thể làm:

apply(sapply(a, function(vec) {b %in% vec}), 1, which.max)