Powerbi中d3.js的父子json树

时间:2019-05-01 16:57:39

标签: javascript

我现在正在使用power bi D3.js Visual构建客户视觉。 power bi中的D3给了我以下JSON作为输入:

 var arr = [
{ "source" : "BBB", "target" : "AAA"},
{ "source" : "CCC ", "target" : "BBB"},
{ "source" : "DDDD", "target" : "AAA"},
{ "source" : "SSSS", "target" : "CCC"},
{ "source" : "EEEE", "target" : "BBB"},
{ "source" : "FFFF", "target" : "DDDD"},

但是我需要的是:

var arr = 

{
  "source": "AAA",
  "children": [
    { 
      "source": "BBB",
      "children": [
        { "source": "CCC",
           "children": [
               { "source": "SSSS"] },
        { "source": "EEEE" }
      ]
    },
    { "source": "DDDD",
      "children": [
        { "source": "FFFF" },
     ] },

  ]
}

有人可以帮忙用javascript获取这种格式吗?

我对在其他帖子上找到的以下脚本感到厌倦,已经做了一些小的更改,只是无法正常工作。

function unflatten(arr) {
  var tree = [],
      mappedArr = {},
      arrElem,
      mappedElem;

  // First map the nodes of the array to an object -> create a hash table.
  for(var i = 0, len = arr.length; i < len; i++) {
    arrElem = arr[i];
    mappedArr[arrElem.child] = arrElem;
    mappedArr[arrElem.child]['children'] = [];
  }



  for (var id in mappedArr) {
    if (mappedArr.hasOwnProperty(id)) {
    console.log(mappedArr.hasOwnProperty(id))
      mappedElem = mappedArr[id];
      //console.log(mappedElem)
      // If the element is not at the root level, add it to its parent array of children.
      if (mappedElem.parent!="0") {
        mappedArr[mappedElem['parent']]['children'].push(mappedElem);
      }
      // If the element is at the root level, add it to first level elements array.
      else {
        tree.push(mappedElem);
      }
    }
  }
  return tree;
}

1 个答案:

答案 0 :(得分:0)

有很多方法可以解决此问题,这里仅是一种:

const arr = [
  { source: "BBB", target: "AAA" },
  { source: "CCC", target: "BBB" },
  { source: "DDDD", target: "AAA" },
  { source: "SSSS", target: "CCC" },
  { source: "EEEE", target: "BBB" },
  { source: "FFFF", target: "DDDD" }
];

const trunk = arr.find(x => !arr.some(y => y.source === x.target)).target;

const branches = arr.reduce((acc, x) => {
  acc[x.target] = acc[x.target] || [];
  acc[x.target].push(x.source);
  return acc;
}, {});

const tree = buildTree(trunk, branches);

function buildTree(source, branches) {
  const tree = { source };
  if (branches[source]) {
    tree.children = branches[source].map(x => buildTree(x, branches));
  }
  return tree;
}

console.log("Trunk: ", trunk);
console.log("Branches: ", branches);
console.log("Output: ", JSON.stringify(tree, null, 2));

这个想法是你:

  1. 找到树的树干
  2. 找到所有有子的分支
  3. 从树干开始构建树,并以递归方式填充每个分支

进一步的澄清:

arr.find(x => !arr.some(y => y.source === x.target))寻找没有父亲的分支

some()方法测试数组中至少一个元素是否通过测试。在这种情况下,由于它有一个!,它将测试该数组中没有哪个元素具有父级。

find()方法返回没有父亲的第一个分支的值。

如果您考虑使用多个中继,则可以用find()方法代替filter()方法,这将返回所有中继的数组。然后,您必须像这样修改算法:

const arr = [
  { source: "BBB", target: "AAA" },
  { source: "CCC", target: "BBB" },
  { source: "DDDD", target: "AAA" },
  { source: "SSSS", target: "CCC" },
  { source: "EEEE", target: "BBB" },
  { source: "FFFF", target: "DDDD" },
  { source: "XXXX", target: "YYYY" }
];

const trunks = arr.filter(x => !arr.some(y => y.source === x.target));

const branches = arr.reduce((acc, x) => {
  acc[x.target] = acc[x.target] || [];
  acc[x.target].push(x.source);
  return acc;
}, {});

const trees = trunks.map(x => buildTree(x.target, branches));

function buildTree(source, branches) {
  const tree = { source };
  if (branches[source]) {
    tree.children = branches[source].map(x => buildTree(x, branches));
  }
  return tree;
}

console.log("Trunk: ", trunks);
console.log("Branches: ", branches);
console.log("Output: ", JSON.stringify(trees, null, 2));