2011-01-19 10 views
5

Sono nuovo di R e sto cercando di ottenere un controllo sulla famiglia di funzioni apply. Nello specifico, sto cercando di scrivere una funzione di ordine superiore che accetti 2 vettori di caratteri, "host" e "guest" (che non devono necessariamente avere la stessa lunghezza) e restituiscono un vettore di indice della stessa lunghezza di "host" ", con gli elementi risultanti corrispondenti ai loro indici in guest (NA se non lì).Come posso vettorializzare questa funzione per restituire un vettore indice?

host <- c("A","B","C","D") 
guest <- c("D","C","A","F") 

matchIndices <- function(x,y) 
{ 
    return(match(x,y)) 
} 

Questo codice restituisce 3 come previsto: (? Sapply)

matchIndices(host[1],guest) 

Questo è il ciclo mi piacerebbe essere in grado di sostituire con una funzione di applicare succinta

Questo codice "funziona" nel senso che produce l'output sotto, ma voglio davvero che il risultato sia un vettore, e ho la sensazione che una delle funzioni applicative farà il trucco. Sono solo bloccato su come scriverlo. Qualsiasi aiuto sarebbe più apprezzato. Grazie.

3; A; NA; B; 2; C; 1; D;

risposta

8
host <- c("A","B","C","D") 
guest <- c("D","C","A","F") 

matchIndices <- function(x,y) { 
    return(match(x,y)) 
} 

Un modo (inefficiente) è quello di sapply il host vettore, passando guest come argomento (nota si può solo semplificare questo a sapply(host, match, guest), ma questo illustra un modo generale di avvicinarsi a questo genere di cose):

> sapply(host, matchIndices, guest) 
A B C D 
3 NA 2 1 

Tuttavia, questo può essere fatto direttamente usando match dato che accetta un vettore primo argomento:

> match(host, guest) 
[1] 3 NA 2 1 

Se si desidera un vettore chiamato come uscita,

> matched <- match(host, guest) 
> names(matched) <- host 
> matched 
A B C D 
3 NA 2 1 

che potrebbe essere avvolto in una funzione

matchIndices2 <- function(x, y) { 
    matched <- match(x, y) 
    names(matched) <- x 
    return(matched) 
} 

ritorno

> matchIndices2(host, guest) 
A B C D 
3 NA 2 1 

Se davvero vuole i nomi e le partite si sono unite in un vettore di stringhe, quindi:

> paste(match(host, guest), host, sep = ";") 
[1] "3;A" "NA;B" "2;C" "1;D" 
+1

si può solo fare 'sapply (host, partita, ospite) ', non c'è bisogno di definire' matchIndices' –

+0

@Prasad Sì, si potrebbe, ma ho lasciato questo come fosse per mostrare come a fiacco una funzione utente in questo modo. Il motivo per cui l'ho lasciato è che tutto questo può essere fatto con 'match' direttamente mentre accetta un vettore first argument. Vedi la mia risposta aggiornata. –

+0

Questo è favoloso. Grazie mille. "match (host, guest)" è perfetto. Non avevo capito che poteva essere così compatto. – user297400

3

se si desidera che il vettore di uscita nel formato host;guestNum si userebbe do.call, paste, match come segue:

> do.call(paste, list(host, sapply(host, match, guest), sep = ';'))                      
[1] "A;3" "B;NA" "C;2" "D;1" 
+2

Come ho già detto, non c'è bisogno di 'sapply' affatto qui; 'match' prende un primo argomento vettoriale, quindi possiamo semplificarlo a' do.call (incolla, lista (host, match (host, guest), sep = ';')) 'ma sembra un po 'eccessivo raggiungere 'paste (match (host, guest), host, sep ="; ")' o 'paste (host, match (host, guest), sep ="; ")' no? –

+0

molto vero @ Gavin, questo è il modo più semplice –

+0

dannatamente, hai ragione. Quindi 'do.call (incolla, lista (host, match (host, guest), sep ="; "))' farebbe –

2
sapply(host , function(x) which(guest==x)) 
$A 
[1] 3 

$B 
integer(0) 

$C 
[1] 2 

$D 
[1] 1 


unlist(sapply(host , function(x) which(guest==x))) 

    A C D 
    3 2 1 

paste(host, sapply(host , function(x) which(guest==x)), sep=":", collapse=" ") 
[1] "A:3 B:integer(0) C:2 D:1" 
Problemi correlati