问题
What are the R equivalents for these Python list comprehensions:
[(i,j) for i,j in zip(index, Values)]
[(i,j) for i,j in enumerate(Values)]
[(i,j) for i,j in enumerate(range(10,20))] %MWE, indexing or enumerating to
%keep up with the index, there may
%be some parameter to look this up
Example with Output
>>> [(i,j) for i,j in enumerate(range(10,20))]
[(0, 10), (1, 11), (2, 12), (3, 13), (4, 14), (5, 15), (6, 16), (7, 17), (8, 18), (9, 19)]
I have solved this problem earlier with some trick in R but cannot remember anymore, the first idea was itertools -pkg but I am hoping to find a more idiomatic way of doing things.
回答1:
There have been some discussions around list comprehension for R, e.g. here or there. The hash package even offers dictionary-like structure. However, as others said, it is difficult to try to map one language facilities onto another (even if this is what Comparison of programming languages actually offers) without a clear understanding of what it is supposed to be used to. For example, I can mimic Python zip()
in R as follows:
Python
In [1]: x = [1,2,3]
In [2]: y = [4,5,6]
In [3]: zip(x, y)
Out[3]: [(1, 4), (2, 5), (3, 6)]
R
> x <- 1:3
> y <- 4:6
> list(x, y) # gives a simple list
> as.list(paste(x, y)) # three tuples, as a list of characters
> mapply(list, x, y, SIMPLIFY=F) # gives a list of 3 tuples
> rbind(x, y) # gives a 2x3 matrix
As can be seen, this really depends on what you want to do with the result afterwards.
回答2:
Answer for python enumerate
:
In R, a list is ordered (see this answer). Thus, all you need is to index either keys (using names()[i]
) or values (using [[i]]
).
Using seq_along
(alternatively can do for(i in 1:length(mylist)){...}
):
> mylist <- list('a'=10,'b'=20,'c'=30)
> for (i in seq_along(mylist)){
+ print(paste(i,names(mylist)[i],mylist[[i]]))
+ }
[1] "1 a 10"
[1] "2 b 20"
[1] "3 c 30"
Answer for python zip
:
See one of the above answers to mimic the list of tuples. My preference is towards a data frame as shown in BondedDust's answer:
> x <- 1:3
> y <- 4:6
> data.frame(x=x, y=y)
x y
1 1 4
2 2 5
3 3 6
回答3:
If that is the Python print representation of a matrix, then this code:
j <- 10:20
matrix(c(seq_along(j), j), ncol=2)
#------------
[,1] [,2]
[1,] 1 10
[2,] 2 11
[3,] 3 12
[4,] 4 13
[5,] 5 14
[6,] 6 15
[7,] 7 16
[8,] 8 17
[9,] 9 18
[10,] 10 19
[11,] 11 20
You are still leaving those of us who are not Python users in the dark regarding the structure of your desired output. You use the term "list" but the output suggests an ordered set of tuples.
Given @chi's guidance we might also suggest using the very R-centric 'dataframe' structure
x <- 1:3
y <- 4:6
dfrm <- data.frame(x=x, y=y)
... which has the flexibility of a list in terms of column types and the access features of a matrix in terms of row and column indexing. Or one could use hhh's request and create the implicitly indexed values of the j-vector, 10:20
, using the rownames
vector that starts at "1" by default, but which could be altered to become a character vector starting at "0"
dfrm <- data.frame(j=10:20)
dfrm[3, ]
#[1] 12
rownames(dfrm) <- 0:10
dfrm["0",]
# [1] 10
Unfortunately, the unwary will find that dfrm[0, ] is not a happy call, returning vector of length 0.
回答4:
Another option which will create a list of vectors is to use the Map function as seen here by @peterhurford: https://rdrr.io/github/peterhurford/funtools/src/R/zippers.R
> x <- 1:3
> y <- 4:6
> z <- 7:9
> Map(c, x, y, z)
[[1]]
[1] 1 4 7
[[2]]
[1] 2 5 8
[[3]]
[1] 3 6 9
回答5:
In order to use Python style list comprehensions with enumerations, such as enumerated lists, one way is to install List-comprehension package LC
(developed 2018) and itertools package (developed 2015).
List comprehensions in R
You can find the LC
package here.
install.packages("devtools")
devtools::install_github("mailund/lc")
Example
> library(itertools); library(lc)
> lc(paste(x$index, x$value), x=as.list(enumerate(rnorm(5))), )
[[1]]
[1] "1 -0.715651978438808"
[[2]]
[1] "2 -1.35430822605807"
[[3]]
[1] "3 -0.162872340884235"
[[4]]
[1] "4 1.42909760816254"
[[5]]
[1] "5 -0.880755983937781"
where the programming syntax is not yet as clean and polished as in Python but functionally working and its help outlines:
"The syntax is as follows: lc(expr, lists, predicates) where expr is some expression to be evaluated for all elements in the lists, where lists are one or more named lists, where these are specified by a name and an expression name = list_expr, and where predicates are expressions that should evaluated to a boolean value. For example, to get a list of all even numbers, squared, from a list x we can write lc(x ** 2, x = x, x %% 2 == 0). The result of a call to lc is a list constructed from the expressions in expr, for all elements in the input lists where the predicates evaluate to true."
where notice that you can leave the predicates empty for example in the above example.
Python-style itertools and enumerations
You can use R's itertools that is very similar to Python's itertools, further in Cran here
library(itertools)
where described
"Various tools for creating iterators, many patterned after functions in the Python itertools module, and others patterned after functions in the 'snow' package."
Example. enumeration
> for (a in as.list(enumerate(rnorm(5)))) { print(paste(a$index, "index:", a$value))}
[1] "1 index: 1.63314811372568"
[1] "2 index: -0.983865948988314"
[1] "3 index: -1.27096072277818"
[1] "4 index: 0.313193212706331"
[1] "5 index: 1.25226639725357"
Example. enumeration with ZIP
> for (h in as.list(izip(a=1:5, b=letters[1:5]))) { print(paste(h$a, "index:", h$b))}
[1] "1 index: a"
[1] "2 index: b"
[1] "3 index: c"
[1] "4 index: d"
[1] "5 index: e"
回答6:
zip
and enumerate
are not particularly difficult to implement in R:
#' zip(1:5,1:10)
zip <- function(...) {
mapply(list, ..., SIMPLIFY = FALSE)
}
Enumerate is simple to define in terms of zip
:
#' enumerate(l=LETTERS)
enumerate <- function(...) {
zip(ix=seq_along(..1), ...)
}
Since these are proper functions, we can use ...
to make them fairly flexible and terse, and take advantage of mapply's behavior, such as recycling inputs and naming output correctly.
回答7:
# similar to python. return a list of list. Short sequences get recycled.
zip <- function(...){
all.list <- list(...)
ele.names <- names(all.list)
max.length <- max(sapply(all.list, length))
lapply(0:(max.length - 1), function(i) {
res <- lapply(all.list, function(l) l[i %% length(l) + 1])
names(res) <- ele.names
res
})
}
来源:https://stackoverflow.com/questions/9281323/zip-or-enumerate-in-r