【问题标题】:generate nested number sequences R-style生成嵌套的数字序列 R 样式
【发布时间】:2016-03-06 12:44:32
【问题描述】:

我需要生成数列如下:

1 1,2 1,2,3 ... 1,2,3...,n 2 2,3 2,3,4 ... 2,3,4,...,n ... ... n-1 n-1,n n

我来自其他编程语言,循环非常好。但我知道 R 社区更喜欢所谓的向量化操作而不是循环(更有效,尽管我还没有阅读所有关于为什么会这样的细节)。

所以,我首先想到的就是循环。而且我编写的这段代码确实可以完成这项工作(R 大师说 euhh in 3,2,1...)

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 世界中聪明而优雅的解决方案。

【问题讨论】:

  • 第二个解决方案,unlist(accum, rec=FALSE)

标签: r vectorization lapply


【解决方案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)))

【讨论】:

  • 谢谢,但是如何在这个解决方案中拆分序列? (据我所知,这个解决方案会生成一个向量,其中所有序列一个接一个地附加)。我希望每个序列都作为列表中的一个元素,以便稍后对每个序列应用一个函数。
【解决方案2】:

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

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

您在这里拥有的是伪装的列表单子。为了更清楚地说明这一点,请考虑以下内容,这是等效的

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是单位/返回。

在具有列表单子的 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) 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-13
    • 2020-04-08
    • 2015-01-01
    • 1970-01-01
    • 2020-06-06
    • 1970-01-01
    • 1970-01-01
    • 2019-05-09
    相关资源
    最近更新 更多