生成嵌套数字序列R-style

时间:2016-03-06 12:44:32

标签: r vectorization lapply

我需要按如下方式生成数字序列:

1 1,2 1,2,3 ... 1,2,3 ...,N 2 2,3 2,3,4 ... 2,3,4,...,N ... ... n-1个 n-1个,正 Ñ

我来自其他编程语言,其中循环非常好。但是我理解R社区偏爱所谓的矢量化操作而不是循环(更有效率,虽然我没有阅读所有关于其原因的细节)。

所以,我想要做的第一件事就是循环。我写了这个代码,肯定能完成这项工作(R大师说3,2,1中的euhh ......)

n <- 30
accum <- list()
for (x in 1:n) {
    for (y in x:n) {
        accum[[paste(x,y)]] <- x:y
    }
}

但这是丑陋的代码(我觉得效率不高)。

那么,对于我的问题,什么是聪明的R风格代码?

我当然没有掌握矢量化操作和应用族函数。但我最好的一点是:

n <- 30
accum <- lapply(1:n, FUN = function(x){lapply(x:n, FUN = seq, from = x)})

不知道这是不是很好的R风格编码,但几乎完成了工作。此解决方案的问题在于它生成一个包含n元素的列表,这些元素也是列表并包含序列。但我想要的是一个包含465个元素的列表(在n = 30的情况下),因此每个序列只有一个元素,而没有该解决方案产生的所有列表嵌套。

我真的很感激R世界中聪明而优雅的解决方案。

2 个答案:

答案 0 :(得分:1)

获取单个载体:

n <- 4
u <- sequence(n:1)
(v <- sequence(u) + rep(1:n, rev(cumsum(1:n))) - 1)
# [1] 1 1 2 1 2 3 1 2 3 4 2 2 3 2 3 4 3 3 4 4

和矢量列表:

split(v, rep(cumsum(u), u))

或与您的解决方案非常相似的东西:

Reduce('c', lapply(1:n, function(x) lapply(x:n, seq, from = x)))

答案 1 :(得分:1)

你的第二个解决方案是好的。您所要做的只是unlist一层。

unlist(lapply(1:n, FUN = function(x) lapply(x:n, FUN = seq, from = x)), rec=FALSE)

这里有你的伪装名单monad。为了更清楚,请考虑以下内容,这是等效的

mapcat <- function(x,f,...) unlist(lapply(x,f,...),rec=FALSE)
mapcat(1:n,function(a) mapcat(a:n, function(b) list(seq(a,b))))

此处mapcat是绑定操作,list是单位/返回。

在具有列表monad的do-notation的语言中,这可以写成,例如在Haskell中,作为

do
  a <- [1..n]
  b <- [a..n]
  return([a..b])

我不知道任何带有这种糖的R包,但使用foreach库,我们可以更接近

library(foreach)
foreach(a=1:n, .combine='c') %:% foreach(b=a:n) %do% seq(a,b)