有趣的非平凡问题!
重大更新发生了这一切,我重写了答案并消除了一些死胡同。我还对不同案例的各种解决方案进行了计时。
这是第一个相当简单但缓慢的解决方案:
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
...的结果