`Reduce`而不是`<< -`

时间:2014-10-10 14:54:34

标签: r map reduce

让我们有一个将列表转换为准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"

但请注意<<-的使用,这是非常尴尬的。

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

1 个答案:

答案 0 :(得分:2)

这里唯一的小问题是,当您在命名列表上使用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"

基本上我们首先缓存节点的转换值,然后查找所有&#39; {xx}&#39;令牌并用相应的值替换它们。