2012-06-12 12 views
10

Dato un elenco a contenenti vettori di lunghezza diversa e un vettore b contenente alcuni elementi dai vettori in a, voglio ottenere un vettore di lunghezza uguale a b contenente l'indice in a dove l'elemento in b partite (questa è una cattiva spiegazione che conosco) ...modo veloce di ottenere indice della partita nella lista

il seguente codice fa il lavoro:

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 

Sostituzione del sapply con un ciclo for ottiene lo stesso di cours e

Il problema è che questo codice verrà utilizzato con elenchi e vettori con una lunghezza superiore a 1000. Su una vita reale impostata la funzione impiega circa 15 secondi (sia il ciclo for che lo sapply).

Qualcuno ha un'idea di come accelerare, sicuro per un approccio parallelo? Non sono riuscito a vedere un approccio vettoriale (e non posso programmare in C, anche se probabilmente sarebbe il più veloce).

Edit:

limito a sottolineare elegante soluzione con la partita di Aaron(), che ha dato un aumento di velocità dell'ordine di 1667 volte (da 15 a 0.009)

ho ampliato un po 'su di esso per consentire a più partite (il ritorno è quindi un elenco)

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 

il tempo di esecuzione per questo era 0,169, che è senza dubbio molto più lento, ma d'altra parte più flessibile

0.123.516,41 mila
+2

Cosa si vuole che l'algoritmo faccia se un elemento di 'b' appare in più di un elemento di' a'? È possibile nel tuo problema attuale? –

+0

Avrei dovuto specificare che ... Non è una possibilità – ThomasP85

risposta

12

Ecco una possibilità con 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 è un'altra opzione:

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

Per restituire un elenco, provate questo:

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

Da 15 secondi a 0.009 - questo è un miglioramento notevole. Ho scoperto che mi piacerebbe davvero restituire una lista invece di un vettore, in modo che possa gestire più corrispondenze. Ho sostituito l'ultima riga del tuo primo suggerimento con sapply (b, function (x) g [che (unlist (a)% in% x)]) per raggiungere questo obiettivo. Il tempo di esecuzione è stato quindi di 0,169, che è molto più lento del tuo ma è comunque un miglioramento importante. – ThomasP85

0

Come commento al tuo post suggerisce , dipende da cosa vuoi fare se/quando lo stesso elemento appare in più vettori in a. Supponendo che si desideri l'indice più basso che si possa fare:

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