在具有多个值的表达式替换一个符号

问题描述 投票:2回答:2

给定任意固定的表情,我想替换一个符号具有多个值的集合。例子:

Expression       | Symbol | Replace with               | Desired Output
-----------------------------------------------------------------------------------------
f(x, 5)          | x      | a = 1, b = sym, c = "char" | f(a = 1, b = sym, c = "char", 5)
g(f(h(y)), z)    | y      | 1, 2, 3                    | g(f(h(1, 2, 3)), z)
g(f(h(y), z), z) | z      | 4, x                       | g(f(h(y), 4, x), 4, x)

substitute()功能接近,但它不正是我所期待的。在下面的例子中,我想转成f(x) f(1, b = 4, c = d),但我还没有找到合适的env说法。

substitute(
  expr = f(x),
  env = list(x = list(1, b = 4, c = rlang::sym("d")))
)
#> f(list(1, b = 4, c = d))

substitute(
  expr = f(x),
  env = list(x = as.call(c(quote(x), 1, b = 4, c = quote(d)))[-1])
)
#> f(1(b = 4, c = d))

reprex package创建于2019年2月9日(v0.2.1)

是否有可能找到一个env这样substitute(f(x), env)等于f(1, b = 4, c = d)

备注:

r metaprogramming static-code-analysis
2个回答
1
投票

这里有一个拼接功能的纺丝

splice <- function(x, replacements) {
  if (is(x, "call")) {
    as.call(do.call("c",lapply(as.list(x), splice, replacements), quote=T))
  } else if (is(x, "name")) {
    if (deparse(x) %in% names(replacements)) {
      return(replacements[[deparse(x)]])
    } else {
      list(x)
    }
  } else {
    list(x)
  }
}

这似乎与样品的输入工作

splice(quote(f(x, 5) ), list(x=list(a = 1, b = quote(sym), c = "char" )))
# f(a = 1, b = sym, c = "char", 5)
splice(quote(g(f(h(y)), z)) , list(y=list(1,2,3)))
# g(f(h(1, 2, 3)), z)
splice(quote(g(f(h(y), z), z)), list(z=list(4, quote(x))) )
# g(f(h(y), 4, x), 4, x)

基本上你只掉出符号名。它也应该有一个变量替换不在列表中的工作。

splice(quote(f(x,5)), list(x=7))
# f(7, 5)

你基本上需要通过操纵它作为一个列表来重新编写调用。这是tidyverse功能正在做什么幕后。他们拦截当前通话,重新写出来,然后评估新扩展的呼叫。 substitute行不通,因为你不只是用一个数值代替一个符号。您需要更改的要传递给函数的参数数量。


0
投票

这个答案是笨重的,但(我认为)它你需要的;它的灵感来自于(且取自同一行)this Stack Overflow answer了几分相关帖子:

multi_substitute <- function(expr, key, ...) {
    expr <- deparse(substitute(expr))
    key <- deparse(substitute(key))
    # The following line is the bit I got from the mentioned SO answer
    l <- sapply( substitute(list(...)), deparse)[-1] 
    l <- paste(names(l), l, sep = " = ")
    l <- sub("^ = ", "", l)
    l <- paste(l, collapse = ",")
    vals <- deparse(substitute(...))
    result <- sub(key, l, expr)
    return(parse(text = result)[[1]])
}
multi_substitute(f(x), x, 1, b = 4, c = quote(d))
# f(1, b = 4, c = quote(d))

您或许能够得到这一点更优雅或对其进行定制,以更好地满足您的需求。

如果你不希望强制规定的key说法那里,你当然可以改变的,大约相当容易。

© www.soinside.com 2019 - 2024. All rights reserved.