J'ai deux listes
first = list(a = 1, b = 2, c = 3)
second = list(a = 2, b = 3, c = 4)
Je veux fusionner ces deux listes pour que le produit final soit
$a
[1] 1 2
$b
[1] 2 3
$c
[1] 3 4
Y a-t-il une fonction simple pour faire cela ?
J'ai deux listes
first = list(a = 1, b = 2, c = 3)
second = list(a = 2, b = 3, c = 4)
Je veux fusionner ces deux listes pour que le produit final soit
$a
[1] 1 2
$b
[1] 2 3
$c
[1] 3 4
Y a-t-il une fonction simple pour faire cela ?
Ceci est une adaptation très simple de la fonction modifyList par Sarkar. Comme elle est récursive, elle gèrera des situations plus complexes que mapply
le ferait, et elle gérera les situations de noms incompatibles en ignorant les éléments de 'second' qui ne sont pas dans 'first'.
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
Voici deux options, la première :
both <- list(first, second)
n <- unique(unlist(lapply(both, names)))
names(n) <- n
lapply(n, function(ni) unlist(lapply(both, `[[`, ni)))
et la deuxième, qui fonctionne seulement si elles ont la même structure :
apply(cbind(first, second),1,function(x) unname(unlist(x)))
Les deux donnent le résultat souhaité.
Voici du code que j'ai finalement écrit, basé sur la réponse de @Andrei mais sans l'élégance/simplicité. L'avantage est qu'il permet une fusion récursive plus complexe et différencie également entre les éléments qui doivent être connectés avec rbind
et ceux qui sont simplement connectés avec c
:
# J'ai décidé de déplacer ceci en dehors de la mapply, je ne suis pas sûr que ce soit
# très important pour la vitesse mais j'imagine que redéfinir la fonction
# pourrait prendre du temps
mergeLists_internal <- function(o_element, n_element){
if (is.list(n_element)){
# Remplir les éléments inexistants avec des éléments NA
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]]))
}
}
}
}
# Fusionner maintenant les deux listes
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("Votre longueur ne correspond pas sur les éléments,",
" le nouvel élément (", new_cols , ") !=",
" l'ancien élément (", 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)
}
Voici mon exemple :
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)
Cela donne :
$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
Oui, je sais - peut-être pas la fusion la plus logique mais j'ai une boucle parallèle complexe pour laquelle j'ai dû générer une fonction .combine
plus personnalisée, donc j'ai écrit ce monstre :-)
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.