【问题标题】:Looping over multiple lists with base R使用基本 R 循环多个列表
【发布时间】:2017-09-13 19:29:55
【问题描述】:

在python中我们可以做到这一点..

numbers = [1, 2, 3]
characters = ['foo', 'bar', 'baz']

for item in zip(numbers, characters):
    print(item[0], item[1])

(1, 'foo')
(2, 'bar')
(3, 'baz')

我们也可以解包元组而不是使用索引。

for num, char in zip(numbers, characters):
    print(num, char)

(1, 'foo')
(2, 'bar')
(3, 'baz')

我们如何使用基础 R 来做同样的事情?

【问题讨论】:

标签: r


【解决方案1】:

要以 R 原生方式执行此类操作,您需要使用数据框的概念。一个数据框有多个变量,这些变量可以是不同的类型,每一行都是对每个变量的观察。

d <- data.frame(numbers = c(1, 2, 3),
                characters = c('foo', 'bar', 'baz'))
d
##   numbers characters
## 1       1        foo
## 2       2        bar
## 3       3        baz

然后您使用矩阵表示法访问每一行,其中将索引留空包括所有内容。

d[1,]
##   numbers characters
## 1       1        foo

然后你可以循环遍历数据框的行来做任何你想做的事情,大概你真的想做一些比打印更有趣的事情。

for(i in seq_len(nrow(d))) {
  print(d[i,])
}
##   numbers characters
## 1       1        foo
##   numbers characters
## 2       2        bar
##   numbers characters
## 3       3        baz

【讨论】:

  • 开车投票不加评论?不酷。走出阴影,帮助改进答案!
  • 我没有投反对票,但你在这里所做的最好通过应用函数 imho 来实现?
【解决方案2】:

对于另一个选项,mapply 怎么样,这是我在 R 中能想到的最接近 zip 的模拟。这里我使用 c 函数来创建一个新向量,但你可以使用任何你想要的函数'想要:

numbers<- c(1, 2, 3)
characters<-  c('foo', 'bar', 'baz')
mapply(c,numbers, characters, SIMPLIFY = FALSE)

[[1]]
[1] "1"   "foo"

[[2]]
[1] "2"   "bar"

[[3]]
[1] "3"   "baz"

哪种方式最有用取决于您想对输出做什么,但正如其他答案所提到的,数据框是 R 中最自然的方法(可能是 python 中的 pandas 数据框)。

【讨论】:

    【解决方案3】:

    要在 R 中索引一个向量,其中向量是变量x 将是 x[1]。这将返回向量的第一个元素。 R 元素编号从 1 开始,而 Python 从 0 开始。

    对于这个问题,应该是:

    x = seq(1,10)
    j = seq(11,20)
    
    for (i in 1:length(x)){
    
        print (c(x[i],j[i]))
    }
    

    【讨论】:

      【解决方案4】:

      R 中的许多函数都是矢量化的,不需要循环:

      numbers = c(1, 2, 3)
      characters = c('foo', 'bar', 'baz')
      myList <- list(numbers, characters)
      myDF <- data.frame(numbers,characters, stringsAsFactors = F)
      
      print(myList)
      print(myDF)
      

      【讨论】:

        【解决方案5】:

        这是概念上的等价物:

        for (item in Map(list,numbers,characters)){ # though most of the time you would actually do all your work inside Map
          print(item[c(1,2)])
        }
        
        # [[1]]
        # [1] 1
        # 
        # [[2]]
        # [1] "a"
        # 
        # [[1]]
        # [1] 2
        # 
        # [[2]]
        # [1] "b"
        # 
        # [[1]]
        # [1] 3
        # 
        # [[2]]
        # [1] "c"
        # 
        # [[1]]
        # [1] 4
        # 
        # [[2]]
        # [1] "d"
        # 
        # [[1]]
        # [1] 5
        # 
        # [[2]]
        # [1] "e"
        

        虽然大多数时候你实际上会在 Map 中完成所有工作并执行以下操作:

        Map(function(nu,ch){print(data.frame(nu,ch))},numbers,characters)
        

        这是我能得到的最接近克隆的:

        zip <- function(...){ Map(list,...)}
        print2 <- function(...){do.call(cat,c(list(...),"\n"))}
        
        for (item in zip(numbers,characters)){
          print2(item[[1]],item[[2]])
        }
        
        # 1 a 
        # 2 b 
        # 3 c 
        # 4 d 
        # 5 e
        

        能够通过名称调用项目(仍然适用于索引):

        zip <- function(...){
          names <- sapply(substitute(list(...))[-1],deparse)
          Map(function(...){setNames(list(...),names)}, ...)
        }
        
        for (item in zip(numbers,characters)){
          print2(item[["numbers"]],item[["characters"]])
        }
        

        【讨论】:

          【解决方案6】:

          tidyverse 的解决方案是使用purrr::map2 函数。例如:

          numbers <- c(1, 2, 3)
          characters <- c('foo', 'bar', 'baz')
          
          map2(numbers, characters, ~paste0(.x, ',', .y))
          
          #[[1]]
          #[1] "1,foo"
          
          #[[2]]
          #[1] "2,bar"
          
          #[[3]]
          #[1] "3,baz"
          

          参见 API here

          【讨论】:

            【解决方案7】:

            其他可扩展的替代方案:将向量存储在列表中并迭代。

            vect1 <- c(1, 2, 3)
            vect1 <- c('foo', 'bar', 'baz')
            vect2 <- c('a', 'b', 'c')
            
            
            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))
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多