Intéressant non négligeable de problème!
Mise à JOUR MAJEURE Avec tout ce qui est arrivé, j'ai réécrit la réponse et la suppression de quelques impasses. J'ai également chronométré les différentes solutions sur les différents cas.
Voici la première, plutôt simple, mais lente, de la solution:
flatten1 <- function(x) {
y <- list()
rapply(x, function(x) y <<- c(y,x))
y
}
rapply
vous permet de parcourir une liste et d'appliquer une fonction sur chaque élément leaf. Malheureusement, il fonctionne exactement comme unlist
avec les valeurs renvoyées. J'ai donc ignorer le résultat d' rapply
et au lieu de cela j'ai ajouter des valeurs à la variable y
en effectuant <<-
.
Croissante y
de cette manière n'est pas très efficace (c'est quadratique en temps). Donc si il y a plusieurs milliers d'éléments, ce sera très lent.
Une approche plus efficace est la suivante, avec les simplifications de @JoshuaUlrich:
flatten2 <- function(x) {
len <- sum(rapply(x, function(x) 1L))
y <- vector('list', len)
i <- 0L
rapply(x, function(x) { i <<- i+1L; y[[i]] <<- x })
y
}
Ici, j'ai d'abord consulter le résultat de la longueur et de pré-allouer le vecteur. Puis-je remplir les valeurs.
Comme vous pouvez le voir, cette solution est beaucoup plus rapide.
Voici une version de @JoshO Brien grande solution basée sur Reduce
, mais étendue, donc il gère profondeur arbitraire:
flatten3 <- function(x) {
repeat {
if(!any(vapply(x, is.list, logical(1)))) return(x)
x <- Reduce(c, x)
}
}
Maintenant que la bataille commence!
# Check correctness on original problem
x <- list(NA, list("TRUE", list(FALSE), 0L))
dput( flatten1(x) )
#list(NA, "TRUE", FALSE, 0L)
dput( flatten2(x) )
#list(NA, "TRUE", FALSE, 0L)
dput( flatten3(x) )
#list(NA_character_, "TRUE", FALSE, 0L)
# Time on a huge flat list
x <- as.list(1:1e5)
#system.time( flatten1(x) ) # Long time
system.time( flatten2(x) ) # 0.39 secs
system.time( flatten3(x) ) # 0.04 secs
# Time on a huge deep list
x <-'leaf'; for(i in 1:11) { x <- list(left=x, right=x, value=i) }
#system.time( flatten1(x) ) # Long time
system.time( flatten2(x) ) # 0.05 secs
system.time( flatten3(x) ) # 1.28 secs
...De sorte que ce que nous observons, c'est que l' Reduce
solution est plus rapide lorsque la profondeur est faible, et l' rapply
solution est plus rapide lorsque la profondeur est grande!
Que de la cohérence va, voici quelques tests:
> dput(flatten1( list(1:3, list(1:3, 'foo')) ))
list(1L, 2L, 3L, 1L, 2L, 3L, "foo")
> dput(flatten2( list(1:3, list(1:3, 'foo')) ))
list(1:3, 1:3, "foo")
> dput(flatten3( list(1:3, list(1:3, 'foo')) ))
list(1L, 2L, 3L, 1:3, "foo")
Difficile de ce résultat est souhaitée, mais je me penche vers le résultat de l' flatten2
...