Zwei Listen in R zusammenführen

Antworten:

111

Wenn Listen immer die gleiche Struktur haben wie im Beispiel, ist eine einfachere Lösung

mapply(c, first, second, SIMPLIFY=FALSE)
Andrei
quelle
30
Dies ist gleichbedeutend mit Map(c, first, second), wenn es jemanden interessiert.
Masterfool
2
Ich lerne gerade R, warum hat Map (und Mapply) 'c' als ersten Parameter? Sollten die übergebenen Parameter nicht einfach die beiden Listen sein?
user391339
3
'c' ist der Name einer primitiven Funktion, die Listen erstellt. Wenn Sie c in R ohne die nachfolgenden Parens eingeben, wird 'function (..., recursive = FALSE) .Primitive ("c")' angezeigt. Dieses Klischee ordnet also die 'c'-Funktion dem Inhalt von first und second zu.
Chris Warth
2
@ Masterfool mapply () ist ein Häkchen effizienter, da Map()enthältmapply()
Comfort Eagle
Wie ernst müssen wir Sorge über die folgenden mapply Warnung: ‚länger Argument nicht ein Vielfaches der Länge kürzer‘
3pitt
24

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
IRTFM
quelle
12

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.

Aaron verließ Stack Overflow
quelle
Ich glaube nicht, dass Ihre zweite richtig funktioniert, da ich anstelle einer Liste von Vektoren ein Matrixdesign erhalte.
Tyler Rinker
Du hast recht; applyvereinfacht es, wenn es kann. Es funktioniert, wenn es nicht vereinfacht werden kann, wie zum Beispiel wenn first$c <- c(4,5).
Aaron verließ Stack Overflow am
Der erste gibt mir eine Liste mit der Länge = 0. sollen Namen als etwas definiert werden?
3pitt
Haben Ihre Listen Namen?
Aaron verließ Stack Overflow
4

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 rbinddenen verbunden werden soll, und solchen, die nur verbunden sind mit c:

# 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 .combineFunktion generieren musste , und deshalb habe ich dieses Monster geschrieben :-)

Max Gordon
quelle
1

Im Allgemeinen könnte man,

merge_list <- function(...) by(v<-unlist(c(...)),names(v),base::c)

Beachten Sie, dass die by()Lösung eine attributed-Liste zurückgibt , sodass sie anders gedruckt wird, aber dennoch eine Liste ist. Aber Sie können die Attribute mit loswerden attr(x,"_attribute.name_")<-NULL. Sie können wahrscheinlich auch verwenden aggregate().

csta
quelle