【问题标题】:Access name of the object that "i" represents when it iterates in a for-loop through a list of objects in R“i”在for循环中遍历R中的对象列表时表示的对象的访问名称
【发布时间】:2019-11-18 15:05:38
【问题描述】:

我有:

  • 包含文件的目录(比如说两个:A 和 B);
  • 存储目录的两个字符对象(dir_Adir_B);
  • 一个将目录作为参数并返回在那里找到的文件名列表的函数(对我来说这是一种方便的方式,不同于list.files())。
directories <- c(dir_A, dir_B)
read_names <- function(x) {foo}

使用 for 循环,我想创建对象,每个对象都包含 read_names() 给出的不同目录的文件列表。本质上,我想使用一个 for 循环来做相当于:

files_A <- read_names(dir_A)
files_B <- read_names(dir_B)

我写的循环如下:

for (i in directories) {
  assign(paste("files_", sub('.*\\_', '', deparse(substitute(i))), sep = ""), read_names(i))
}

但是,尽管在 for 循环之外 deparse(substitute(dir_A)) 返回“dir_A”(因此,上面编写的 sub() 函数将返回“A”),但在我看来,在 for 循环中 @ 987654330@ 使i 不再是目录之一,而只是i

因此deparse(substitute(i))返回"i",上面for循环的输出只有一个名为files_i的对象,它包含迭代最后一个目录中的文件列表,因为那是最后一个在files_i 上被覆盖。

如何让 for 循环读取 i 在那一刻代表的对象的名称(或在我的情况下是名称的一部分,但它是相同的)?

【问题讨论】:

  • 写入directories &lt;- c(dir_A, dir_B) 后,变量dir_A 没有关联,只有执行创建目录的语句时dir_A 的值。

标签: r for-loop iteration objectname


【解决方案1】:

我认为这里有两个问题:

  1. 如何引用list 中每个元素的名称(或索引)和值;和
  2. 如何将数据从命名list 传输到全局(或任何)环境中。

1。引用数据的名称/索引

使用for (i in directories) 编制索引后,directories 内的i 的完整上下文(索引、名称)将丢失。一些替代方案:

for (ix in seq_along(directories)) {
   directories[[ix]]             # the *value*
   names(directories)[ix]        # the *name*
   ix                            # the *index*
   # ...
}

for (nm in names(directories)) {
   directories[[nm]]             # the *value*
   nm                            # the *name*
   match(nm, names(directories)) # the *index*
   # ...
}

如果您愿意使用类似Map 的函数(处理类似事物列表的更惯用方式),那么

out <- Map(function(x, nm) {
  x                              # the *value*
  nm                             # the *name*
   # ...
}, directories, names(directories))

out <- purrr::imap(directories, function(x, nm) {
  x                              # the *value*
  nm                             # the *name*
   # ...
})
# there are other ways to identify the function in `purrr::` functions

注意:虽然在最后两个中使用match 来获取索引很容易,但我更愿意在合理的情况下避免这种轻微的范围违规。它有效,我只是更喜欢替代方法。如果你想要值、名称、索引,那么

out <- Map(function(x, nm, ix) {
  x                              # the *value*
  nm                             # the *name*
  ix                             # the *index*
   # ...
}, directories, names(directories), seq_along(directories))

2。将列表传输到 env

在您的问题中,您这样做是为了将列表中的变量分配到另一个环境中。关于努力的一些想法:

  1. 如果它们都相似(相同的结构,不同的数据),则不要。将它们保存在list 中,并使用lapply 或类似方法对它们进行整体处理。 (How do I make a list of data frames?)

  2. 如果您确实需要将它们从列表移动到全局环境,那么list2env 在这里可能很有用。

    # create my fake data
    directories <- list(a=1, b=2)
    # this is your renaming step, rename before storing in the global env
    # ... not required unless you have no names or want/need different names
    names(directories) <- paste0("files_", names(directories))
    # here the bulk of the work; you can safely ignore the return value
    list2env(directories, envir = .GlobalEnv)
    # <environment: R_GlobalEnv>
    ls()
    # [1] "directories" "files_a"     "files_b"    
    files_a
    # [1] 1
    

【讨论】:

  • 感谢您的回答。我是编码新手,所以我需要花点时间才能真正理解你的推理所暗示的一切。同时,我尝试使用names(directories) 技巧来解决它,但该函数一直返回NULL(当我尝试使用示例虚拟对象时也是如此)。但通常只是完成工作才是关键,所以我找到了一种解决方法,先使用names_directories &lt;- sort(grep("dir_", (names(environment()), value = TRUE),然后在循环中的paste() 中使用names_directories[i]。也许不是最有效的,但现在还可以。 @G5W 也帮助我意识到。
  • names(directories) of NULL 表示它没有名字。
  • 是的,现在我明白了这一点——但在我看来,这只是改变问题所在。如果我只有两个目录,那么我可以去directories &lt;- c(dir_A = dir_A, dir_B = dir_B)。但是,如果我想自动化这个过程,那么我会回到同样的问题上。但我想这不是关于最初的问题,而是关于我掌握 R 和编程的更多信息。无论如何,我又在考虑这个问题,并意识到在某种意义上我可以不用费心去创建这些对象,而是在需要时继续使用read_names()——这可能是你的最后一点。
猜你喜欢
  • 2013-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-28
  • 2019-12-11
  • 2013-05-16
  • 2023-03-28
  • 2012-09-12
相关资源
最近更新 更多