有没有办法在 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 中应用它的实际方法是什么?
缺口
有没有办法在 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 中应用它的实际方法是什么?
缺口
像这样的东西?
l <- 1:1000
sum(l[l %% 3 == 0 | l %% 5 == 0])
是的,列表理解在 R 中是可能的:
sum((1:1000)[(1:1000 %% 3) == 0 | (1:1000 %% 5) == 0])
而且,(有点)对scala的理解:
for(i in {x <- 1:100;x[x%%2 == 0]})print(i)
另一种方式
sum(l<-(1:1000)[l %% 3 == 0 | l %% 5 == 0])
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
这是多年后的事了,但现在 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
我希望可以自我推广我的包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
此列表理解形式:
[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))
您可以将随机数序列转换为二进制序列,如下所示:
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 )