【问题标题】:Getting name of an object from list in Map从 Map 中的列表中获取对象的名称
【发布时间】:2018-12-13 14:51:11
【问题描述】:

给定以下数据:

list_A <- list(data_cars = mtcars,
               data_air = AirPassengers,
               data_list = list(A = 1,
                                B = 2))

我想打印list_A 中可用对象的名称。

示例:

Map(
    f = function(x) {
        nm <- deparse(match.call()$x)
        print(nm)
        # nm object is only needed to properly name flat file that may be
        # produced within Map call
        if (any(class(x) == "list")) {
            length(x) + 1
        } else {
            length(x) + 1e6
            saveRDS(object = x,
                    file = tempfile(pattern = make.names(nm), fileext = ".RDS"))
        }
    },
    list_A
)

返回:

[1] "dots[[1L]][[1L]]"
[1] "dots[[1L]][[2L]]"
[1] "dots[[1L]][[3L]]"
$data_cars
NULL

$data_air
NULL

$data_list
[1] 3

期望的结果

我想得到:

`data_cars`
`data_air`
`data_list`

更新

在 cmets 之后,我修改了示例,使其更能反映我的实际需求,即:

  • 在使用 Map 迭代 list_A 时,我正在对列表的每个元素执行一些操作
  • 我想定期创建一个平面文件,其名称反映已处理对象的名称
  • 除了list_A,还有list_Blist_C等等。因此,我想避免在Map 的函数f 中调用names(list),因为我将不得不修改它n 次。我正在寻找的解决方案应该适用于:

    Map(function(l){...}, list_A)
    

    所以我以后可以替换list_A。它不必依赖Map。任何 函数都可以;同样适用于基于 的解决方案。


替代示例

do_stuff <- function(x) {
    nm <- deparse(match.call()$x)
    print(nm)
    # nm object is only needed to properly name flat file that may be
    # produced within Map call
    if (any(class(x) == "list")) {
        length(x) + 1
    } else {
        length(x) + 1e6
        saveRDS(object = x,
                file = tempfile(pattern = make.names(nm), fileext = ".RDS"))
    }
}

Map(do_stuff, list_A)

根据下面的注释,我想避免修改 do_stuff 函数,因为我将要这样做:

  • Map(do_stuff, list_A)
  • Map(do_stuff, list_B)
  • Map(do_stuff, list_...)

【问题讨论】:

  • names(list_A) 有什么问题?
  • 我不清楚为什么names(list_A) 不适合您。你能建立一个更好的例子来说明原因吗?
  • 您是在问如何遍历名称和数据?如果是这种情况,您可以使用purrr::map2(list_A, names(list_A), ~ .y) 并通过.x 访问相应的数据元素。如果这不是您要找的东西,我也很困惑为什么 names(list_A) 不是您要找的东西。
  • @MHammer 我还认为 OP 可能想要迭代 list_A 保留名称。当base 解决方案等效时,我只是建议避免使用外部包(尤其是具有大量依赖项的purrrr)。例如Map(function(x,y) dosomethingWithNamesAndValues, list_A, names(list_A)).
  • Map 不会传递列表元素的名称。所以我同意你可能需要做类似do_stuff &lt;- function(x, nm) { do stuff }; Map(do_stuff, list, names(list)).

标签: apply purrr r list function mapping


【解决方案1】:

我们可以把它包装成一个函数,分两步完成:

myFun <- function(myList){
  # do stuff
  res <- Map(
    f = function(x) {
      #do stuff
      head(x)
    },
    myList)

  # write to a file, here we might add control
  # if list is empty do not output to a file
  for(i in names(res)){
    write.table(res[[ i ]], file = paste0(i, ".txt"))
  }
}

myFun(list_A)

【讨论】:

  • 我在想,如果是基于for 的解决方案,我可以使用getlist 开始使用seq_along names。它会起作用,只是让我远离美丽的Map(do_stuff, list_...) 语法。如果没有其他选择,我会接受。我想我可能要求不可能;除非有办法让do_stuff 搜索父环境,找到x 的母对象,然后使用"dots[[n]][[n]]" 字符串子集名称,但这对于恕我直言 应该更简单的东西来说非常繁琐。
  • lapply(names(res), function(i) write.table(res[[i]], file = paste0(i, ".txt")),而不是循环。
  • @Axeman 我也是这么想的,但他们真正的Map 可能更复杂。
  • @Konrad,我想你会发现穿越环境会比它的价值更痛苦。我通常分两步操作和保存,如下所示。
【解决方案2】:

这样的东西有用吗?

list_A2 <- Map(list, x = list_A,nm = names(list_A) )
trace(do_stuff, quote({ nm <- x$nm;  x<- x$x}), at=3)
Map(do_stuff, list_A2)

【讨论】:

  • 很好地使用了tracequote
  • 你能解释一下为什么at=3吗?我想了解您为什么要查看函数的第三步。
  • 我只想在nm &lt;- deparse(match.call()$x) 之后施展魔法,否则我的nm &lt;- x$nm 将被覆盖。 nm &lt;- deparse(match.call()$x) 仍然会发生,但它已被我的代码覆盖。出于某种我不明白的原因,at=1at=2 似乎做同样的事情,所以要将我们的代码放在正确的位置,我们需要at=3。有意义吗?
  • 是的,非常感谢您的解释。
猜你喜欢
  • 1970-01-01
  • 2019-07-30
  • 2012-02-21
  • 1970-01-01
  • 1970-01-01
  • 2015-08-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多