Ich habe zwei Listen
first = list(a = 1, b = 2, c = 3)
second = list(a = 2, b = 3, c = 4)
Ich möchte diese beiden Listen zusammenführen, damit das Endprodukt entsteht
$a
[1] 1 2
$b
[1] 2 3
$c
[1] 3 4
Gibt es eine einfache Funktion, um dies zu tun?
Antworten:
Wenn Listen immer die gleiche Struktur haben wie im Beispiel, ist eine einfachere Lösung
mapply(c, first, second, SIMPLIFY=FALSE)
quelle
Map(c, first, second)
, wenn es jemanden interessiert.Map()
enthältmapply()
Dies ist eine sehr einfache Anpassung der Funktion "modifyList" durch Sarkar. Da es rekursiv ist, werden komplexere Situationen als zuvor behandelt
mapply
, und es werden nicht übereinstimmende Namenssituationen behandelt, indem die Elemente in 'second' ignoriert werden, die nicht in 'first' enthalten sind.appendList <- function (x, val) { stopifnot(is.list(x), is.list(val)) xnames <- names(x) for (v in names(val)) { x[[v]] <- if (v %in% xnames && is.list(x[[v]]) && is.list(val[[v]])) appendList(x[[v]], val[[v]]) else c(x[[v]], val[[v]]) } x } > appendList(first,second) $a [1] 1 2 $b [1] 2 3 $c [1] 3 4
quelle
Hier sind zwei Optionen, die erste:
both <- list(first, second) n <- unique(unlist(lapply(both, names))) names(n) <- n lapply(n, function(ni) unlist(lapply(both, `[[`, ni)))
und die zweite, die nur funktioniert, wenn sie die gleiche Struktur haben:
apply(cbind(first, second),1,function(x) unname(unlist(x)))
Beide ergeben das gewünschte Ergebnis.
quelle
apply
vereinfacht es, wenn es kann. Es funktioniert, wenn es nicht vereinfacht werden kann, wie zum Beispiel wennfirst$c <- c(4,5)
.Hier ist ein Code, den ich am Ende geschrieben habe, basierend auf der Antwort von @ Andrei, aber ohne die Eleganz / Einfachheit. Der Vorteil besteht darin, dass es eine komplexere rekursive Zusammenführung ermöglicht und sich auch zwischen Elementen unterscheidet, mit
rbind
denen verbunden werden soll, und solchen, die nur verbunden sind mitc
:# Decided to move this outside the mapply, not sure this is # that important for speed but I imagine redefining the function # might be somewhat time-consuming mergeLists_internal <- function(o_element, n_element){ if (is.list(n_element)){ # Fill in non-existant element with NA elements if (length(n_element) != length(o_element)){ n_unique <- names(n_element)[! names(n_element) %in% names(o_element)] if (length(n_unique) > 0){ for (n in n_unique){ if (is.matrix(n_element[[n]])){ o_element[[n]] <- matrix(NA, nrow=nrow(n_element[[n]]), ncol=ncol(n_element[[n]])) }else{ o_element[[n]] <- rep(NA, times=length(n_element[[n]])) } } } o_unique <- names(o_element)[! names(o_element) %in% names(n_element)] if (length(o_unique) > 0){ for (n in o_unique){ if (is.matrix(n_element[[n]])){ n_element[[n]] <- matrix(NA, nrow=nrow(o_element[[n]]), ncol=ncol(o_element[[n]])) }else{ n_element[[n]] <- rep(NA, times=length(o_element[[n]])) } } } } # Now merge the two lists return(mergeLists(o_element, n_element)) } if(length(n_element)>1){ new_cols <- ifelse(is.matrix(n_element), ncol(n_element), length(n_element)) old_cols <- ifelse(is.matrix(o_element), ncol(o_element), length(o_element)) if (new_cols != old_cols) stop("Your length doesn't match on the elements,", " new element (", new_cols , ") !=", " old element (", old_cols , ")") } return(rbind(o_element, n_element, deparse.level=0)) return(c(o_element, n_element)) } mergeLists <- function(old, new){ if (is.null(old)) return (new) m <- mapply(mergeLists_internal, old, new, SIMPLIFY=FALSE) return(m) }
Hier ist mein Beispiel:
v1 <- list("a"=c(1,2), b="test 1", sublist=list(one=20:21, two=21:22)) v2 <- list("a"=c(3,4), b="test 2", sublist=list(one=10:11, two=11:12, three=1:2)) mergeLists(v1, v2)
Das führt zu:
$a [,1] [,2] [1,] 1 2 [2,] 3 4 $b [1] "test 1" "test 2" $sublist $sublist$one [,1] [,2] [1,] 20 21 [2,] 10 11 $sublist$two [,1] [,2] [1,] 21 22 [2,] 11 12 $sublist$three [,1] [,2] [1,] NA NA [2,] 1 2
Ja, ich weiß - vielleicht nicht die logischste Zusammenführung, aber ich habe eine komplexe parallele Schleife, für die ich eine individuellere
.combine
Funktion generieren musste , und deshalb habe ich dieses Monster geschrieben :-)quelle
Im Allgemeinen könnte man,
merge_list <- function(...) by(v<-unlist(c(...)),names(v),base::c)
Beachten Sie, dass die
by()
Lösung eineattribute
d-Liste zurückgibt , sodass sie anders gedruckt wird, aber dennoch eine Liste ist. Aber Sie können die Attribute mit loswerdenattr(x,"_attribute.name_")<-NULL
. Sie können wahrscheinlich auch verwendenaggregate()
.quelle