44

有没有办法在 R 中实现列表理解?

像蟒蛇:

sum([x for x in range(1000) if x % 3== 0 or x % 5== 0])

在 Haskell 中也一样:

sum [x| x<-[1..1000-1], x`mod` 3 ==0 || x `mod` 5 ==0 ]

在 R 中应用它的实际方法是什么?

缺口

4

9 回答 9

39

像这样的东西?

l <- 1:1000
sum(l[l %% 3 == 0 | l %% 5 == 0])
于 2013-04-14T11:56:56.087 回答
10

是的,列表理解在 R 中是可能的:

sum((1:1000)[(1:1000 %% 3) == 0 | (1:1000 %% 5) == 0])
于 2013-04-14T11:55:21.250 回答
3

而且,(有​​点)对scala的理解:

for(i in {x <- 1:100;x[x%%2 == 0]})print(i)
于 2013-09-20T16:20:26.727 回答
2

另一种方式

sum(l<-(1:1000)[l %% 3 == 0 | l %% 5 == 0])
于 2015-04-10T09:14:10.960 回答
2

Revolution Analytics的foreach包为我们提供了一个方便的界面来列出 R 中的理解。https://www.r-bloggers.com/list-comprehensions-in-r/

例子

从列表中返回不等于元组的数字:

Python

list_a = [1, 2, 3]
list_b = [2, 7]

different_num = [(a, b) for a in list_a for b in list_b if a != b]

print(different_num) 

# Output: 
[(1, 2), (1, 7), (2, 7), (3, 2), (3, 7)]

R

require(foreach)

list_a = c(1, 2, 3)
list_b = c(2, 7)

different_num  <- foreach(a=list_a ,.combine = c ) %:% foreach(b=list_b) %:% when(a!=b) %do% c(a,b)

print(different_num)

# Output:
         [[1]]
         [1] 1 2

         [[2]]
         [1] 1 7

         [[3]]
         [1] 2 7

         [[4]]
         [1] 3 2

         [[5]]
         [1] 3 7

编辑:
foreach 包对于某些任务非常慢。R的列表推导中给出了更快的列表推导实现

. <<- structure(NA, class="comprehension")

comprehend <- function(expr, vars, seqs, guard, comprehension=list()){
  if(length(vars)==0){  # base case of recursion
    if(eval(guard)) comprehension[[length(comprehension)+1]] <- eval(expr)
  } else {
    for(elt in eval(seqs[[1]])){
      assign(vars[1], elt, inherits=TRUE)
      comprehension <- comprehend(expr, vars[-1], seqs[-1], guard, 
                                  comprehension)
    }
  }
  comprehension
}

## List comprehensions specified by close approximation to set-builder notation:
##
##   { x+y | 0<x<9, 0<y<x, x*y<30 } ---> .[ x+y ~ {x<-0:9; y<-0:x} |  x*y<30 ]
##

"[.comprehension" <- function(x, f,rectangularizing=T){
  f <- substitute(f)
  ## First, we pluck out the optional guard, if it is present:
  if(is.call(f) && is.call(f[[3]]) && f[[3]][[1]]=='|'){
    guard <- f[[3]][[3]]
    f[[3]] <- f[[3]][[2]]
  } else {
    guard <- TRUE
  }
  ## To allow omission of braces around a lone comprehension generator,
  ## as in 'expr ~ var <- seq' we make allowances for two shapes of f:
  ##
  ## (1)    (`<-` (`~` expr
  ##                   var)
  ##              seq)
  ## and
  ##
  ## (2)    (`~` expr
  ##             (`{` (`<-` var1 seq1)
  ##                  (`<-` var2 seq2)
  ##                      ...
  ##                  (`<-` varN <- seqN)))
  ##
  ## In the former case, we set gens <- list(var <- seq), unifying the
  ## treatment of both shapes under the latter, more general one.
  syntax.error <- "Comprehension expects 'expr ~ {x1 <- seq1; ... ; xN  <- seqN}'."
  if(!is.call(f) || (f[[1]]!='<-' && f[[1]]!='~'))
    stop(syntax.error)
  if(is(f,'<-')){ # (1)
    lhs <- f[[2]]
    if(!is.call(lhs) || lhs[[1]] != '~')
      stop(syntax.error)
    expr <- lhs[[2]]
    var <- as.character(lhs[[3]])
    seq <- f[[3]]
    gens <- list(call('<-', var, seq))
  } else { # (2)
    expr <- f[[2]]
    gens <- as.list(f[[3]])[-1]
    if(any(lapply(gens, class) != '<-'))
      stop(syntax.error)
  }
  ## Fill list comprehension .LC
  vars <- as.character(lapply(gens, function(g) g[[2]]))
  seqs <- lapply(gens, function(g) g[[3]])
  .LC <- comprehend(expr, vars, seqs, guard)

  ## Provided the result is rectangular, convert it to a vector or array
  if(!rectangularizing) return(.LC)
  tryCatch({
     if(!length(.LC))
      return(.LC)
  dim1 <- dim(.LC[[1]])
  if(is.null(dim1)){
    lengths <- sapply(.LC, length)
    if(all(lengths == lengths[1])){ # rectangular
      .LC <- unlist(.LC)
      if(lengths[1] > 1) # matrix
        dim(.LC) <- c(lengths[1], length(lengths))
    } else { # ragged
      # leave .LC as a list
    }
  } else { # elements of .LC have dimension
    dim <- c(dim1, length(.LC))
    .LC <- unlist(.LC)
    dim(.LC) <- dim
  }
  return(.LC)
  }, error = function(err) {
    return(.LC)
  })

}

这个实现比 foreach 更快,它允许嵌套理解、多个参数和参数范围。

 N <- list(10,20)
.[.[c(x,y,z)~{x <- 2:n;y <- x:n;z <- y:n} | {x^2+y^2==z^2 & z<15}]~{n <- N}]

[[1]]
[[1]][[1]]
[1] 3 4 5

[[1]][[2]]
[1]  6  8 10


[[2]]
[[2]][[1]]
[1] 3 4 5

[[2]][[2]]
[1]  5 12 13

[[2]][[3]]
[1]  6  8 10
于 2018-11-13T14:47:32.120 回答
2

这是多年后的事了,但现在 CRAN 上有三个列表理解包。每个都有略微不同的语法。按字母顺序:

library(comprehenr)
sum(to_vec(for(x in 1:1000) if (x %% 3 == 0 | x %% 5 == 0) x))
## [1] 234168

library(eList)
Sum(for(x in 1:1000) if (x %% 3 == 0 | x %% 5 == 0) x else 0)
## [1] 234168

library(listcompr)
sum(gen.vector(x, x = 1:1000, x %% 3 == 0 | x %% 5 == 0))
## [1] 234168

此外,以下内容仅在 github 上。

# devtools::install.github("mailund/lc")
library(lc)
sum(unlist(lc(x, x = seq(1000), x %% 3 == 0 | x %% 5 == 0)))
## [1] 234168
于 2021-02-10T00:38:42.840 回答
1

我希望可以自我推广我的包listcompr,它实现了 R 的列表理解语法。

问题中的示例可以通过以下方式解决:

library(listcompr)
sum(gen.vector(x, x = 1:1000, x %% 3 == 0 || x %% 5 == 0))

## Returns: 234168

由于 listcompr 对条件进行逐行(而不是矢量虎钳)评估,因此如果使用|||使用逻辑运算符则没有区别。它接受任意多个参数:首先,转换为列表或向量条目的基本表达式。接下来,指定变量范围和条件的任意多个参数。

更多示例可以在 listcompr 的 github 存储库的 readme 页面上找到:https ://github.com/patrickroocks/listcompr

于 2021-01-16T08:41:36.110 回答
0

此列表理解形式:

[item for item in list if test]

在 R 中使用布尔索引非常简单。但是对于更复杂的表达式,例如实现矢量重新缩放(我知道这也可以通过 scales 包完成),在 Python 中很容易:

x = [1, 3, 5, 7, 9, 11] # -> [0.0, 0.2, 0.4, 0.6, 0.8, 1.0]
[(xi - min(x))/(max(x) - min(x)) for xi in x]

但在 R 中,这是我能想到的最好的。想知道是否有更好的东西:

sapply(x, function(xi, mn, mx) {(xi-mn)/(mx-mn)}, mn = min(x), mx = max(x))
于 2018-07-03T19:32:32.650 回答
0

您可以将随机数序列转换为二进制序列,如下所示:

x=runif(1000)
y=NULL
for (i in x){if (i>.5){y<-c(y,1)}else{y=c(y,-1)}}

这可以概括为在任何列表上操作到另一个列表,基于:

x = [item for item in x if test == True]

测试可以使用 else 语句不附加列表 y。

对于手头的问题:

x <- 0:999 
y <- NULL 
for (i in x){ if (i %% 3 == 0 | i %% 5 == 0){ y <- c(y, i) }}
sum( y )
于 2018-07-10T02:39:00.167 回答