从内部提取中获取对象名称

时间:2018-06-05 08:00:10

标签: r extract

我想编写一个函数gnl()(getNamesLike),当在extract中进行求值时,可以检索执行extract的对象的名称。 是可能

以下是一些所需行为的代码:

gnl <- function(pattern) {grepl(pattern,names(mtcars))}
mtcars[,gnl("a")] %>% head
#                   drat am gear carb
# Mazda RX4         3.90  1    4    4
# Mazda RX4 Wag     3.90  1    4    4
# Datsun 710        3.85  1    4    1
# Hornet 4 Drive    3.08  0    3    1
# Hornet Sportabout 3.15  0    3    2
# Valiant           2.76  0    3    1

gnl <- function(pattern) {grepl(pattern,names(cars))}
cars[,gnl("i"),drop=F]  %>% head
#   dist
# 1    2
# 2   10
# 3    4
# 4   22
# 5   16
# 6   10

当然gnl()需要动态获取名称(mtcars,汽车等等)。

我得到的最多的是:

gnl <- function(data,pattern) {
    dplyr::select(data,dplyr::matches(pattern))
    }
mtcars %>% gnl("a")

2 个答案:

答案 0 :(得分:1)

这似乎有效,但有点像黑客..

dig_call <- function(call, call0_chr) {

  new_call <- call[[which(grepl(call0_chr, call, fixed = TRUE))]]

  if (identical(deparse(new_call), call0_chr)) {
    call[[2]]
  } else {
    dig_call(new_call, call0_chr)
  }
}

gnl <- function(pattern) {

  call0_chr <- deparse(sys.call(i <- 0))

  repeat {
    i <- i + 1
    call <- sys.call(i)
    find_call <- grepl(call0_chr, call, fixed = TRUE)
    if (any(find_call)) break
  }

  grepl(pattern, names(eval(dig_call(call, call0_chr), parent.frame())))
}

原理:

  1. 您迭代检查调用堆栈,直到您通过gnl进行一次调用

  2. 此调用可能由许多调用组成(例如,%>% head()调用),因此您需要递归地挖掘这些调用以仅获取具有gnl的调用

  3. 此调用的第二个元素为您提供了您尝试子集的对象的名称(例如,查看as.list(substitute(mtcars[1]))

  4. 您对此对象执行过滤

  5. 验证

    library(dplyr)
    cars[gnl("i")]
    cars[gnl("i")] %>% head()
    cars[gnl("i")] %>% head() %>% head()
    mtcars[gnl("i")]
    mtcars[gnl("i")] %>% head()
    

答案 1 :(得分:1)

额外的S3课程:

`[.gnlable` <- function(x, i, j, drop = FALSE) {
  if (!missing(j)) {
    j <- substitute(j)
    j <- if (identical(j[[1]], quote(gnl))) grepl(j[[2]], names(x)) else eval(j)
  }
  `[.data.frame`(x, i, j, drop = drop)
}

class(cars) <- c("gnlable", class(cars))

cars[1:6, gnl("i"), drop = FALSE]
#   dist
# 1    2
# 2   10
# 3    4
# 4   22
# 5   16
# 6   10