興味深い重要な問題!
メジャーアップデートすべてが起こったので、私は答えを書き直し、いくつかの行き止まりを取り除きました。また、さまざまなケースでさまざまなソリューションのタイミングを調整しました。
これが最初の、かなり単純ですが遅い解決策です:
flatten1 <- function(x) {
y <- list()
rapply(x, function(x) y <<- c(y,x))
y
}
rapply
リストをトラバースして、各リーフ要素に関数を適用できます。unlist
残念ながら、戻り値とまったく同じように機能します。したがって、からの結果を無視し、代わりにを実行rapply
して変数に値を追加します。y
<<-
この方法で成長y
させることはあまり効率的ではありません(時間的には二次的です)。したがって、何千もの要素がある場合、これは非常に遅くなります。
より効率的なアプローチは次のとおりですが、@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
}
ここでは、最初に結果の長さを見つけて、ベクトルを事前に割り当てます。次に、値を入力します。ご覧のとおり、このソリューションははるかに高速です。
これは、に基づく@ JoshO'Brienの優れたソリューションのバージョンですがReduce
、任意の深さを処理するように拡張されています。
flatten3 <- function(x) {
repeat {
if(!any(vapply(x, is.list, logical(1)))) return(x)
x <- Reduce(c, x)
}
}
さあ、戦いを始めましょう!
# 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
...つまりReduce
、深さが浅いrapply
場合は解が速くなり、深さが大きい場合は解が速くなることがわかります。
正しさとして、ここにいくつかのテストがあります:
> 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")
flatten2
どのような結果が望まれるかは不明ですが、私は...からの結果に傾いています。