2016-01-06 23 views
11

Ich habe eine Liste von Listen von Zeichen. Zum Beispiel:Konvertieren Sie eine Liste von Listen in einen Zeichenvektor

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

So wie Sie einige Elemente sind Listen der Länge sehen können> 1.

Ich mag diese Liste von Listen, um ein Zeichen Vektor konvertieren, aber ich würde die Listen mit Länge mag > 1 erscheint als einzelnes Element im Zeichenvektor.

die unlist Funktion erreicht nicht das, sondern eher:

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

Gibt es etwas schneller als:

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

Zu meinem gewünschten Ergebnis:

"A" "B" "CD" 
+3

'vapply'? Ist 'sapply' in diesem Fall langsam? – A5C1D2H2I1M1N2O1R2T1

+4

"Paste" nur auf die Teile von "l" anwenden, die "Länge> 1" und dann "Nichtliste" sind? Und ersetzen Sie 'sapply' durch' vapply', wie Ananda vorschlägt, ein wenig mehr Geschwindigkeit herauszusuchen. – thelatemail

Antwort

16

Sie können überspringen der Unlist-Schritt. Sie dachten schon, dass paste0collapse = TRUE zu „binden“ sequentielle Elemente eines Vektors zusammen benötigt:

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

Hier ist eine Variation von @ thela Vorschlag, wenn Sie nicht ein mehrzeiliges Ansatz nichts dagegen tun:

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" 

Alternativ, wenn es Ihnen nichts ausmacht ein Paket zu verwenden, sehen Sie sich das Paket "stringi" an, speziell stri_flatten, wie von @Jota vorgeschlagen.


Hier ist ein Performance-Vergleich:

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 

Hinweis: Die relative Effizienz dieses Ansatzes würde davon abhängen, wie viele Listenelemente length(x) > 1 haben werden. Wenn die meisten von ihnen sowieso > 1 sein werden, dann gehen Sie einfach mit @ 42-Ansatz. stri_flatten verbessert nur die Leistung, wenn Sie lange Zeichenvektoren zusammenfügen, wie in der Beispielliste, die für den obigen Benchmark verwendet wird, sonst hilft es nicht.

+0

Danke für das Schreiben - ich habe R nicht vor mir im Moment :-) – thelatemail

+0

@Jota, fügte die Option hinzu und CWd die Antwort. Bitte zögern Sie nicht, andere Alternativen zu bearbeiten und hinzuzufügen. – A5C1D2H2I1M1N2O1R2T1

Verwandte Themen