【问题标题】:Creating R list as config object in JavaScript style以 JavaScript 样式创建 R 列表作为配置对象
【发布时间】:2015-02-04 12:41:21
【问题描述】:

我需要一个配置对象来保持我的 R 代码中使用的一些常量。这些是远程文件的 url、保存下载文件的目录、下载后要使用的本地文件名等。 我是 R 新手,这就是为什么我决定使用类似 JavaScript 的配置对象(尤其是列表),类似于以下内容:

var config = {
    wd           : "/some/working/dir",
    zipSrc       : "http://www.example.com/remote_data_file.zip",
    data_dir     : "data",
    data_zip     : "data.zip",
    data_txt     : "data.txt",
    abs_data_dir : this.wd + this.data_dir,
    abs_data_zip : this.abs_data_dir + this.data_zip,
    abs_data_txt : this.abs_data_dir + this.data_txt
};

请注意,可以使用“this”来引用当前对象并在其中进行一些计算/分配。

我在R中到达的最远的地方是:

config <- list(wd           = getwd(),
               zipSrc       = "http://www.example.com/remote_data_file.zip",
               data_dir     = "data",
               data_zip     = "data.zip",
               data_txt     = "data.txt")

但是如果仍然需要计算 abs_data_dir 和其他类似值怎么办?是否可以在“构建”配置列表对象时完成这项工作?是否可以基于刚刚创建的列表成员派生新的命名列表成员,例如在 dplyr 包中使用 mutate() ?如果是这样,在 R 中是否有任何类似于 JS 的“this”来引用当前对象?

【问题讨论】:

    标签: r configuration this config


    【解决方案1】:

    解决方案 1

    想到within,玩了一会才想到这个:

    config = rev(within(list(), {
       wd           = "/some/working/dir"
       zipSrc       = "http://www.example.com/remote_data_file.zip"
       data_dir     = "data"
       data_zip     = "data.zip"
       data_txt     = "data.txt"
       abs_data_dir = file.path(wd, data_dir)
       abs_data_zip = file.path(abs_data_dir, data_zip)
       abs_data_txt = file.path(abs_data_dir, data_txt)
    }))
    
    config
    # $wd
    # [1] "/some/working/dir"
    
    # $zipSrc
    # [1] "http://www.example.com/remote_data_file.zip"
    
    # $data_dir
    # [1] "data"
    
    # $data_zip
    # [1] "data.zip"
    
    # $data_txt
    # [1] "data.txt"
    
    # $abs_data_dir
    # [1] "/some/working/dir/data"
    
    # $abs_data_zip
    # [1] "/some/working/dir/data/data.zip"
    
    # $abs_data_txt
    # [1] "/some/working/dir/data/data.txt"
    

    你可以把它变成一个函数:

    list.eval <- function(...) rev(within(list(), ...))
    

    如下调用list.eval({a = 1; b = a})


    解决方案 2

    这是另一个使用更接近list 的函数。它还将处理命名和未命名的参数,如 list 所做的:

    list.eval <- function(...) {
       e <- new.env()
       argl <- as.list(sys.call())[-1L]
       naml <- names(argl)
       .eval.assign <- function(expr, name) {
          value <- eval(expr, envir = e)
          if (name != "") assign(name, value, envir = e)
          return(value)
       }
       setNames(Map(.eval.assign, argl, naml), naml)
    }
    
    z <- 10
    list.eval(a = 1, b = z, c = a, 10)
    # $a
    # [1] 1
    # 
    # $b
    # [1] 10
    # 
    # $c
    # [1] 1
    # 
    # [[4]]
    # [1] 10
    

    【讨论】:

    • 解决方案 1 对于 R 新手来说似乎更简单、更容易理解。谢谢你,弗洛德尔,非常感谢!
    【解决方案2】:

    这可能不如 Flodel 的解决方案美观,但您可以使用环境而不是列表,例如:

    mk_config <- function (expr) {
        env <- new.env()
        evalq(expr, envir = env)
        function (s) get(s, envir = env)
    }
    

    语法不像dplyr::mutate:你只要写一段代码:

    CF_ <- mk_config({
        wd           <- "/some/working/dir"
        zipSrc       <- "http://www.example.com/remote_data_file.zip"
        data_dir     <- "data"
        data_zip     <- "data.zip"
        data_txt     <- "data.txt"
        abs_data_dir <- file.path(wd, data_dir)
        abs_data_zip <- file.path(abs_data_dir, data_zip)
        abs_data_txt <- file.path(abs_data_dir, data_txt)
    })
    
    CF <- function (e) CF_(deparse(substitute(e)))
    

    这样做的一个可能优点是,如果您缺少密钥而不是返回 NULLget 会失败并出现错误:

    CF(abs_data_txt)
    
    ## [1] "/some/working/dir/data/data.txt"
    
    CF(abs_dtaa_txt)
    
    ## Error in get(s, envir = env) (from cf.R#4) : object 'abs_dtaa_txt' not found
    ## Calls: CF -> CF_ -> get
    

    您还可以从文件中加载配置选项,例如

    local(source('config.R', local = TRUE), envir = env)
    

    【讨论】:

    • 非常好的闭包使用示例!谢谢你,塞缪尔!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多