Zip or enumerate in R?

RIndexingEnumerate

R Problem Overview


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.

R Solutions


Solution 1 - R

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

Solution 2 - R

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.

Solution 3 - R

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.

Solution 4 - R

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

Solution 5 - R

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.

Solution 6 - R

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"

Solution 7 - R

For python, 'enumerate' equivalent in R. Storing the vectors in the list and iterating over them with an index should work fine.

vect1 <- c('A', 'B', 'C')
vect2 <- c('a', 'b', 'c')

# eqiv to zip values:
idx_list <- list(vect1, vect2)
idx_vect <- c(1:length(idx_list[[1]]))

for(i in idx_vect){
    x <- idx_list[[1]][i]
    j <- idx_list[[2]][i]
    print(c(i, x, j))
}

Output:

[1] "1" "A" "a"
[1] "2" "B" "b"
[1] "3" "C" "c"

R 'list' is a nice bank for depositing the vectors and retain with an index.

Solution 8 - R

# 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
    })
}

Solution 9 - R

This can be achieved using two paste statements:

str1 <- paste(1:11, 10:20, sep=",", collapse='), (')
paste("(", str1, ")", sep = "")

Output will like following:

'(1,10), (2,11), (3,12), (4,13), (5,14), (6,15), (7,16), (8,17), (9,18), (10,19), (11,20)'

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionhhhView Question on Stackoverflow
Solution 1 - RTheja TulabandhulaView Answer on Stackoverflow
Solution 2 - RchlView Answer on Stackoverflow
Solution 3 - RNeal FultzView Answer on Stackoverflow
Solution 4 - RwphamptonView Answer on Stackoverflow
Solution 5 - RIRTFMView Answer on Stackoverflow
Solution 6 - RhhhView Answer on Stackoverflow
Solution 7 - RSuryaView Answer on Stackoverflow
Solution 8 - RLeafView Answer on Stackoverflow
Solution 9 - RkraviView Answer on Stackoverflow