从索引中获取列表元素名称

Posted

技术标签:

【中文标题】从索引中获取列表元素名称【英文标题】:Get list element name from index 【发布时间】:2020-07-27 15:38:14 【问题描述】:

我正在尝试使用以下 glue 代码来创建信息丰富的错误消息

library(rlang)
library(glue)

my_function <- function(x) 
  UseMethod("my_function", x)


my_function.default <- function(x) 
  abort(glue(
    "Can't calculate my_function because  deparse(substitute(x))  is of type ",
    glue_collapse(class(x))
  ))

使用这个测试列表,我们看到它有效:

test <- list(
  x = c(1,2,3),
  y = c("one", "two", "three")
)

my_function(test[[1]])
Error: Can't calculate my_function because test[[1]] is of type numeric
Run `rlang::last_error()` to see where the error occurred. 

但是是否可以使用glue 来让错误返回x,它说test[[1]] 导致错误:

Can't calculate my_function because x is of type numeric

【问题讨论】:

我希望它返回列表元素的名称,所以如果我现在执行 my_function(test[[2]]) 它将返回“无法计算 my_function,因为 y 是字符类型” 你想要列表元素的名字 当您传入test[[1]] 时,您也不会传入名称。你可以编写代码来处理这个问题,但是你也可以为my_function(test$x)my_function(fun_that_returns_list())my_function(1:3)这样的情况编写特殊代码——在这些情况下会发生什么?如果您总是期望一个列表,那么您可能需要为列表本身和子集参数指定单独的参数。 如果在里面是不可能的。您可以传递两个参数,一个是列表和名称,这样会更容易 R 中任何类型的正常评估都不可能。值不知道它们在列表中的事实。只有列表知道它们的值的情况。 【参考方案1】:

这是一个挖掘索引表达式以推断被索引元素的名称的函数。简而言之,它将遵循list[index] 模式的表达式转换为names(list)[index],同时对list$name 已经在表达式中具有名称很聪明。

getElementNames <- function(ee) 
    ## Determine if ee is an indexing operation
    eel <- as.list(ee)
    isIdx <- purrr::map_lgl(exprs( `[`, `[[`, `$` ),
                            identical, eel[[1]])

    ## If not, return the expression itself as a string
    if(!any(isIdx)) return( deparse(ee) )

    ## The name may already be in the expression
    if( is.name(eel[[3]]) || is.character(eel[[3]]) )
        return( as.character(eel[[3]]) )

    ## Compose an expression indexing the names
    nms <- eval.parent(expr( names(!!eel[[2]])[!!eel[[3]]] ))

    ## Names might be missing
    `if`( is.null(nms), deparse(ee), nms )

实际作用:

test  <- list(a=4, b=5, c=6)
test2 <- 1:3
ftest <- function(x) abort(glue("Can't calculate getElementNames(substitute(x))"))

ftest( test[[2]] )    # index by numeric value
# Error: Can't calculate b

ftest( test$c )       # index by name
# Error: Can't calculate c

ftest( test[["a"]] )  # another way to index by name
# Error: Can't calculate a

i <- 2; j <- 3
ftest( test[i:j] )    # index multiple elements
# Error: Can't calculate b
# * Can't calculate c

ftest( test2[3] )     # index something with no names
# Error: Can't calculate test2[3]

ftest( fun_that_returns_list() )  # non-indexing expression
# Error: Can't calculate fun_that_returns_list()

ftest( 1:3 )                      # another non-indexing expression
# Error: Can't calculate 1:3

【讨论】:

以上是关于从索引中获取列表元素名称的主要内容,如果未能解决你的问题,请参考以下文章

如何从列表“StandardListItem”中的 JSON 文件中的元素“名称”中获取所有值?

Linq + Reflection通过字段名称和条件从列表中获取元素

列表中的索引元素[重复]

根据名称将列表元素替换为另一个列表元素

如何双击列表中具有相同 ID、索引和名称的元素

获取列表中最小元素少于特定元素的最快方法