RSON列表或数据框到JSON

时间:2014-02-05 19:42:27

标签: json r list d3.js

我正在尝试在R中创建一个与flare.json的D3树结构相对应的参差不齐的列表。我的数据在data.frame中:

path <- data.frame(P1=c("direct","direct","organic","direct"),
P2=c("direct","direct","end","end"),
P3=c("direct","organic","",""),
P4=c("end","end","",""), size=c(5,12,23,45))

path
       P1     P2      P3  P4 size
1  direct direct  direct end    5
2  direct direct organic end   12
3 organic    end               23
4  direct    end               45

但它也可以是一个列表或在必要时重新塑造:

path <- list()
path[[1]] <- list(name=c("direct","direct","direct","end"),size=5)
path[[2]] <- list(name=c("direct","direct","organic","end"), size=12)
path[[3]] <- list(name=c("organic", "end"), size=23)
path[[4]] <- list(name=c("direct", "end"), size=45)

所需的输出是:

rl <- list()
rl <- list(name="root", children=list())
rl$children[1] <- list(list(name="direct", children=list()))
rl$children[[1]]$children[1] <- list(list(name="direct", children=list()))
rl$children[[1]]$children[[1]]$children[1] <- list(list(name="direct", children=list()))
rl$children[[1]]$children[[1]]$children[[1]]$children[1] <- list(list(name="end", size=5))

rl$children[[1]]$children[[1]]$children[2] <- list(list(name="organic", children=list()))
rl$children[[1]]$children[[1]]$children[[2]]$children[1] <- list(list(name="end",    size=12))

rl$children[[1]]$children[2] <- list(list(name="end", size=23))

rl$children[2] = list(list(name="organic", children=list()))
rl$children[[2]]$children[1] <- list(list(name="end", size=45))

所以,当我打印到json时,它是:

require(RJSONIO)
cat(toJSON(rl, pretty=T))

 {
"name" : "root",
"children" : [
    {
        "name" : "direct",
        "children" : [
            {
                "name" : "direct",
                "children" : [
                    {
                        "name" : "direct",
                        "children" : [
                            {
                                "name" : "end",
                                "size" : 5
                            }
                        ]
                    },
                    {
                        "name" : "organic",
                        "children" : [
                            {
                                "name" : "end",
                                "size" : 12
                            }
                        ]
                    }
                ]
            },
            {
                "name" : "end",
                "size" : 23
            }
        ]
    },
    {
        "name" : "organic",
        "children" : [
            {
                "name" : "end",
                "size" : 45
            }
        ]
    }
]
}

我很难围绕在R中创建此列表结构所需的递归步骤。在 JS 中,我可以非常轻松地在节点周围移动,并在每个节点确定是否添加新节点或根据需要使用推送继续向下移动树,例如:new = {"name": node, "children": []};new = {"name": node, "size": size};,如此example。我尝试split这个example中的 makeList<-function(x){ if(ncol(x)>2){ listSplit<-split(x,x[1],drop=T) lapply(names(listSplit),function(y){list(name=y,children=makeList(listSplit[[y]]))}) } else { lapply(seq(nrow(x[1])),function(y){list(name=x[,1][y],size=x[,2][y])}) } } jsonOut<-toJSON(list(name="root",children=makeList(path)))

 Error: evaluation nested too deeply: infinite recursion / options(expressions=)?
 Error during wrapup: evaluation nested too deeply: infinite recursion / options(expressions=)?

但它给了我一个错误

{{1}}

2 个答案:

答案 0 :(得分:1)

linked Q&A中给出的函数基本上是您所需要的,但是由于后面列中某些行的空值,它在数据集上失败了。你需要检查你的“结束”值,然后用它来切换到制作叶子,而不是盲目地重复递归,直到用完列为止:

makeList<-function(x){
    listSplit<-split(x[-1],x[1], drop=TRUE);
    lapply(names(listSplit),function(y){
        if (y == "end") { 
            l <- list();
            rows = listSplit[[y]];
            for(i in 1:nrow(rows) ) {
               l <- c(l, list(name=y, size=rows[i,"size"] ) );
            }
            l;

       }
        else {
             list(name=y,children=makeList(listSplit[[y]]))
        }
    });
}

答案 1 :(得分:0)

我相信这会做你想要的,虽然它有一些局限性。特别是,假设您网络中的每个分支都是唯一的(即数据框中不能有两行对于除大小之外的每一列都相同):

df.split <- function(p.df) {
  p.lst.tmp <- unname(split(p.df, p.df[, 1]))
  p.lst <- lapply(
    p.lst.tmp, 
    function(x) {
      if(ncol(x) == 2L && nrow(x) == 1L) {
        return(list(name=x[1, 1], size=unname(x[, 2])))
      } else if (isTRUE(is.na(unname(x[ ,2])))) {
        return(list(name=x[1, 1], size=unname(x[, ncol(x)])))
      }
      list(name=x[1, 1], children=df.split(x[, -1, drop=F]))
    }
  )
  p.lst
}
all.equal(rl, df.split(path)[[1]])
# [1] TRUE

虽然请注意您已切换有机尺寸,但我必须修复您的rl才能获得此结果(rl将其设为45,但您的path为23)。另外,我稍微修改了path data.frame:

path <- data.frame(
  root=rep("root", 4),
  P1=c("direct","direct","organic","direct"),
  P2=c("direct","direct","end","end"),
  P3=c("direct","organic",NA,NA),
  P4=c("end","end",NA,NA), 
  size=c(5,12,23,45), 
  stringsAsFactors=F
)

警告:我没有对其他结构进行测试,所以它可能会遇到你需要调试的极端情况。