2014-10-10 78 views
1

让我们是一种把列表转换成准JSON字符串的函数:`Reduce`,而不是`<< - `

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()

+0

为什么不写一个'for'循环?似乎更容易 – konvas 2014-10-10 15:53:46

+0

想学习MapReduce风格。此外,应避免循环。 – 2014-10-10 15:58:28

+1

for循环的糟糕用法绝对应该避免。在你的情况下,for循环很好,因为你只是循环遍历'seq_along(nodes)'并且只更新循环内的变量'query',所以非常好。 – konvas 2014-10-10 16:00:45

回答

2

这里唯一的一个小问题是,当您在命名列表上使用Reduce时,您无权访问函数中的名称。一种解决方法就是将名称与数据一起嵌入。你可以做一个像Map(list, names(nodes), nodes)这样的转换。然后,一旦你有这样的对象,你可以在iteratete有你需要的所有信息,你可以使用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}”令牌和相应的值替换它们。

+0

非常感谢你!在'regmatches'方法中,不是大括号混淆而是:'m < - gregexpr(“\\ {[^]} + \\}”,query)'? – 2014-10-10 16:05:04

+0

@DanielKrizian号他们在我写的答案中是正确的。基本上角色类匹配是除了末端大括号之外的所有内容。 – MrFlick 2014-10-10 17:25:53

相关问题