2016-01-06 36 views
11

Ho un elenco di elenchi di caratteri. Per esempio:Convertire un elenco di elenchi in un vettore di caratteri

l <- list(list("A"),list("B"),list("C","D")) 

Quindi, come potete vedere alcuni elementi sono liste di lunghezza> 1.

voglio convertire questo elenco di liste per un vettore di carattere, ma mi piacerebbe le liste con lunghezza > 1 per apparire come un singolo elemento nel vettore dei caratteri.

la funzione unlist non raggiunge quello ma piuttosto:

> unlist(l) 
[1] "A" "B" "C" "D" 

ci sia qualcosa di più veloce di:

sapply(l,function(x) paste(unlist(x),collapse="")) 

per ottenere il mio risultato desiderato:

"A" "B" "CD" 
+3

'vapply'? In questo caso, 'sapply' è lento? – A5C1D2H2I1M1N2O1R2T1

+4

Applicare solo "incolla" alle parti di "l" che sono "lunghezza> 1", quindi "non elencato"? E sostituisci 'sapply' con' vapply' mentre Ananda suggerisce di fare un po 'più di velocità. – thelatemail

risposta

16

Si può saltare il passo non elencato. È già capito che paste0 bisogno collapse = TRUE a "legare" gli elementi sequenziali di un vettore insieme:

> sapply(l, paste0, collapse="") 
[1] "A" "B" "CD" 
6

Ecco una variazione di suggestione @ di thela, se non ti dispiace un approccio multi-line:

x <- lengths(l)          ## Get the lengths of each list 
l[x > 1] <- lapply(l[x > 1], paste0, collapse = "") ## Paste only those together 
unlist(l, use.names = FALSE)      ## Unlist the result 
# [1] "A" "B" "CD" 

In alternativa, se non ti dispiace usare un pacchetto, guarda il pacchetto "stringi", in particolare stri_flatten, come suggerito da @Jota.


Ecco un confronto delle prestazioni:

l <- list(list("A"), list("B"), list("B"), list("B"), list("B"), 
      list("C","D"), list("E","F", "G", "H"), 
      as.list(rep(letters,10)), as.list(rep(letters,2))) 
l <- unlist(replicate(1000, l, FALSE), recursive = FALSE) 

funop <- function() sapply(l,function(x) paste(unlist(x),collapse="")) 
fun42 <- function() sapply(l, paste0, collapse="") 
funv <- function() vapply(l, paste0, character(1L), collapse = "") 
funam <- function() { 
    x <- lengths(l) 
    l[x > 1] <- lapply(l[x > 1], paste0, collapse = "") 
    unlist(l, use.names = FALSE) 
} 
funj <- function() sapply(l, stri_flatten) 
funamj <- function() { 
    x <- lengths(l) 
    l[x > 1] <- lapply(l[x > 1], stri_flatten) 
    unlist(l, use.names = FALSE) 
} 

library(microbenchmark) 
microbenchmark(funop(), fun42(), funv(), funam(), funj(), times = 20) 
# Unit: milliseconds 
#  expr  min  lq  mean median  uq  max neval cld 
# funop() 78.21822 84.79588 85.30055 85.36399 86.90540 90.48321 20  e 
# fun42() 56.16938 57.35735 61.60008 58.04969 65.82836 81.46482 20 d 
# funv() 54.64101 56.23245 60.07896 57.26049 63.96815 78.58043 20 d 
# funam() 45.89760 46.89890 48.99810 47.29617 48.28764 56.92544 20 c 
# funj() 28.73405 29.94041 32.00676 30.56711 31.11448 39.93765 20 b 
# funamj() 18.64829 19.01328 21.05989 19.12468 19.52516 32.87569 20 a 

Nota: L'efficienza relativa di questo approccio dipenderà da quanti elementi di una lista stanno per avere length(x) > 1. Se la maggior parte di loro sarà comunque > 1, allora segui l'approccio di @ 42-s. stri_flatten migliora solo le prestazioni se si dispone di vettori di caratteri lunghi da incollare insieme come nella lista di campioni utilizzata per il benchmark sopra, altrimenti non aiuta.

+0

Grazie per averlo scritto - Non ho R di fronte a me al momento :-) – thelatemail

+0

@Jota, aggiunto l'opzione e CWd la risposta. Non esitate a modificare e aggiungere altre alternative. – A5C1D2H2I1M1N2O1R2T1