Быстрый способ получить индекс соответствия в списке
Учитывая список a
, содержащий векторы неравной длины и вектор b
, содержащий некоторые элементы из векторов в a
, я хочу получить вектор равной длины b
, содержащий индекс в a
где элемент в b
соответствует (это плохое объяснение, которое я знаю)...
Следующий код выполняет задание:
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
Замена sapply
на цикл for обеспечивает то же самое, конечно,
Проблема заключается в том, что этот код будет использоваться со списком и векторами длиной более 1000. В реальном наборе времени функция занимает около 15 секунд (как для цикла цикла, так и для sapply
).
У кого-нибудь есть идея, как ускорить это, безопасно для параллельного подхода? Я не видел векторный подход (и я не могу программировать на C, хотя это, вероятно, было бы самым быстрым).
Edit:
Просто подчеркнем элегантное решение Aaron, используя match(), который дал увеличение скорости в порядке 1667 раз (от 15 до 0.009)
Я немного расширил его, чтобы разрешить несколько совпадений (возврат - это список)
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
Время выполнения для этого было 0.169, что, возможно, было довольно медленным, но, с другой стороны, более гибким
Ответы
Ответ 1
Здесь одна возможность с использованием 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
- это еще один вариант:
> findInterval(match(b, unlist(a)), cumsum(c(0,sapply(a, length)))+1)
[1] 1 1 2 3
Чтобы вернуть список, попробуйте следующее:
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)]
Ответ 2
Как следует из комментария к вашему сообщению, это зависит от того, что вы хотите сделать, если/когда один и тот же элемент появляется в нескольких векторах в a
. Предполагая, что вам нужен самый низкий индекс, который вы могли бы сделать:
apply(sapply(a, function(vec) {b %in% vec}), 1, which.max)