2014-10-10 99 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