【问题标题】:`Reduce` instead of `<<-``减少`而不是`<<-`
【发布时间】:2014-12-05 18:58:59
【问题描述】:

让我们有一个将列表转换为准 JSON 字符串的函数:

as.cypher.list = function(l){
  dots = l
  reserved = c("ID", "label")
  properties = dots[!names(dots) %in% reserved]
  properties = gsub("',", "', ",                             # adds spaces after commas
                    gsub('"', "'",                             # replaces " with '
                         gsub('"([^"]+)":', "\\1:",              # removes " around key names
                              toJSON(rapply(properties, as.character)))))
  label = if(is.null(dots[["label"]])) "" else paste0(":", dots[["label"]])
  ID = if(is.null(dots[["ID"]])) NA_character_ else dots[["ID"]]
  query = sprintf("%s%s", label, properties)
  return(query)
}

例如:

as.cypher.list(list(label="AA", a=1, b="foo", name="bar"))
# [1] ":AA{a:'1', b:'foo', name:'bar'}"

现在让我们来:

query = "MATCH {n}, {ae} RETURN n"
nodes = list(n=list(label="AA", a=1, b="foo", name="bar"),
             ae=list(label="BB", b=2))

如何将nodes 列表中的值替换为query,以便每个列表名称与query 中的子字符串匹配?替换后的最终理想结果是:

query
# [1] "MATCH (n:AA{a:'1', b:'foo', name:'bar'}), (ae:BB{b:'2'}) RETURN n"

我可以这样做:

add_param = function(nm, val){
  query <<- gsub(paste0("{", nm, "}"), 
                 paste0("(", nm, as.cypher.list(val),")"), 
                 query, fixed = T)
}

Map(add_param, names(nodes), nodes)
# $n
# [1] "MATCH (n:AA{a:'1', b:'foo', name:'bar'}), {ae} RETURN n"
# 
# $ae
# [1] "MATCH (n:AA{a:'1', b:'foo', name:'vser'}), (ae:BB{b:'2'}) RETURN n"

但是请注意&lt;&lt;- 的使用,这很尴尬。

在这种情况下如何使用Reduce()

【问题讨论】:

  • 你为什么不写一个for循环呢?似乎更容易
  • 想学习 MapReduce 风格。此外,应避免使用 for 循环。
  • 绝对应该避免错误地使用 for 循环。在您的情况下,for 循环很好,因为您将只是循环 seq_along(nodes) 并且只在循环内更新变量 query,所以非常好。

标签: r map reduce


【解决方案1】:

这里唯一的小问题是,当您在命名列表上使用Reduce 时,您无法访问函数中的名称。解决此问题的一种方法是将名称与数据一起嵌入。您可以进行类似Map(list, names(nodes), nodes) 的转换。然后,一旦你有了这个对象,你就可以迭代它有你需要的所有信息,你可以使用Reduce

Reduce(function(q,n) {
    nm <- n[[1]]
    val <- n[[2]]
    gsub(paste0("{", nm, "}"), 
        paste0("(", nm, as.cypher.list(val),")"), 
        q, fixed = T)
}, Map(list, names(nodes), nodes), init=query)
# [1] "MATCH (n:AA{a:'1', b:'foo', name:'bar'}), (ae:BB{b:'2'}) RETURN n"

您也可以考虑使用regmatches() 进行提取/替换。这是一种这样的策略

tnodes <- mapply(function(nm, val) paste0("(", nm, as.cypher.list(val),")"), 
    names(nodes), nodes)
query <- "MATCH {n}, {ae} RETURN n"
m <- gregexpr("\\{[^}]+\\}", query)
regmatches(query, m) <- lapply(regmatches(query, m), function(x) {
    names <- substr(x, 2, nchar(x)-1)
    tnodes[names]
})
query
# [1] "MATCH (n:AA{a:'1', b:'foo', name:'bar'}), (ae:BB{b:'2'}) RETURN n"

基本上我们首先缓存节点的转换值,然后查找所有“{xx}”标记并用相应的值替换它们。

【讨论】:

  • 非常感谢!在regmatches 方法中,大括号不是混淆了,而是:m &lt;- gregexpr("\\{[^]}+\\}", query) ?
  • @DanielKrizian 不。我写的答案是正确的。基本上,字符类匹配是除了大括号之外的所有内容。
猜你喜欢
  • 2019-07-23
  • 2020-06-17
  • 2018-05-23
  • 2018-01-21
  • 1970-01-01
  • 1970-01-01
  • 2022-12-26
  • 2019-05-06
  • 2020-05-30
相关资源
最近更新 更多