2011-11-29 114 views
12

原始JSON数据(平表):转换对象的扁平阵列成对象的嵌套阵列

[ 
    {"id":"1","first_name":"Jason","last_name":"Martin","start_date":"1996-07-25","end_date":"2006-07-25","salary":"1234.56","city":"Toronto","description":"Programmer","department":"Finance","active":"1"}, 
    {"id":"2","first_name":"Alison","last_name":"Mathews","start_date":"1976-03-21","end_date":"1986-02-21","salary":"6661.78","city":"Vancouver","description":"Tester","department":"Finance","active":"1"}, 
    {"id":"3","first_name":"James","last_name":"Smith","start_date":"1978-12-12","end_date":"1990-03-15","salary":"6544.78","city":"Vancouver","description":"Tester","department":"QA","active":"1"}, 
    {"id":"4","first_name":"Celia","last_name":"Rice","start_date":"1982-10-24","end_date":"1999-04-21","salary":"2344.78","city":"Vancouver","description":"Manager","department":"HR","active":"1"}, 
    {"id":"5","first_name":"Robert","last_name":"Black","start_date":"1984-01-15","end_date":"1998-08-08","salary":"2334.78","city":"Vancouver","description":"Tester","department":"IT","active":"1"}, 
    {"id":"6","first_name":"Linda","last_name":"Green","start_date":"1987-07-30","end_date":"1996-01-04","salary":"4322.78","city":"New York","description":"Tester","department":"QA","active":"1"}, 
    {"id":"7","first_name":"David","last_name":"Larry","start_date":"1990-12-31","end_date":"1998-02-12","salary":"7897.78","city":"New York","description":"Manager","department":"HR","active":"1"} 
] 

我需要调用该函数是这样的:

nest(data,["city","description","department"]) 

的第一个参数是整个数据集,第二个是定义嵌套级别的列数组。

预期JSON输出:

[ 
{key: "city", value: "Toronto", count: 1, children: 
    [ 
     {key: "description", value: "Programmer", count: 1, children: 
      [ 
       {key: "department", value: "Finance", count: 1} 
      ] 
     } 
    ] 
}, 
{key: "city", value: "Vancouver", count: 2, children: 
    [ 
     {key: "description", value: "Tester", count: 3, children: 
      [ 
       {key: "department", value: "Finance", count: 1}, 
       {key: "department", value: "QA", count: 1}, 
       {key: "department", value: "IT", count: 1} 
      ] 
     }, 
     {key: "description", value: "Manager", count: 1} 
    ] 
}, 

{key: "city", value: "New York", count: 2, children: 
    [ 
     {key: "description", value: "Tester", count: 1, children: 
      [ 
       {key: "department", value: "QA", count: 1} 
      ] 
     }, 
     {key: "description", value: "Manager", count: 1, children: 
      [ 
       {key: "department", value: "HR", count: 1} 
      ] 
     } 
    ] 
} 

]

我试着写一些递归函数,但保持当我有动态搜索树,以避免重复卡住。

+1

为什么'{关键:“部门”,值“金融”, count:1}'而不是'{key:“department”,value:“Finance”,count:0}'?该节点没有孩子。 –

+0

欢迎来到[SO];请阅读[常见问题]。 – zzzzBov

+0

什么是计数?即使孩子是零时也是1。 – goat

回答

9

认为这是一个有趣的小问题,所以我做到了......但是,我同意那些询问“迄今为止您尝试过什么”的人。通常,你应该谈论一个特定的问题。

// Groups a flat array into a tree. 
// "data" is the flat array. 
// "keys" is an array of properties to group on. 
function groupBy(data, keys) { 

    if (keys.length == 0) return data; 

    // The current key to perform the grouping on: 
    var key = keys[0]; 

    // Loop through the data and construct buckets for 
    // all of the unique keys: 
    var groups = {}; 
    for (var i = 0; i < data.length; i++) 
    { 
     var row = data[i]; 
     var groupValue = row[key]; 

     if (groups[groupValue] == undefined) 
     { 
      groups[groupValue] = new Array(); 
     } 

     groups[groupValue].push(row); 
    } 

    // Remove the first element from the groups array: 
    keys.reverse(); 
    keys.pop() 
    keys.reverse(); 

    // If there are no more keys left, we're done: 
    if (keys.length == 0) return groups; 

    // Otherwise, handle further groupings: 
    for (var group in groups) 
    { 
     groups[group] = groupBy(groups[group], keys.slice()); 
    } 

    return groups; 
} 

调用的方法是这样的:

var groupedData = groupBy(data, ["city","description","department"]); 

此方法为您的数据的输出是这样的:

{ 
    "Toronto": { 
     "Programmer": { 
      "Finance": [ 
       { 
        "id": "1", "first_name": "Jason", "last_name": "Martin", "start_date": "1996-07-25", "end_date": "2006-07-25", "salary": "1234.56", "city": "Toronto", "description": "Programmer", "department": "Finance", "active": "1" 
       } 
      ] 
     } 
    }, 
    "Vancouver": { 
     "Tester": { 
      "Finance": [ 
       { 
        "id": "2", "first_name": "Alison", "last_name": "Mathews", "start_date": "1976-03-21", "end_date": "1986-02-21", "salary": "6661.78", "city": "Vancouver", "description": "Tester", "department": "Finance", "active": "1" 
       } 
      ], 
      "QA": [ 
       { 
        "id": "3", "first_name": "James", "last_name": "Smith", "start_date": "1978-12-12", "end_date": "1990-03-15", "salary": "6544.78", "city": "Vancouver", "description": "Tester", "department": "QA", "active": "1" 
       } 
      ], 
      "IT": [ 
       { 
        "id": "5", "first_name": "Robert", "last_name": "Black", "start_date": "1984-01-15", "end_date": "1998-08-08", "salary": "2334.78", "city": "Vancouver", "description": "Tester", "department": "IT", "active": "1" 
       } 
      ] 
     }, 
     "Manager": { 
      "HR": [ 
       { 
        "id": "4", "first_name": "Celia", "last_name": "Rice", "start_date": "1982-10-24", "end_date": "1999-04-21", "salary": "2344.78", "city": "Vancouver", "description": "Manager", "department": "HR", "active": "1" 
       } 
      ] 
     } 
    }, 
    "New York": { 
     "Tester": { 
      "QA": [ 
       { 
        "id": "6", "first_name": "Linda", "last_name": "Green", "start_date": "1987-07-30", "end_date": "1996-01-04", "salary": "4322.78", "city": "New York", "description": "Tester", "department": "QA", "active": "1" 
       } 
      ] 
     }, 
     "Manager": { 
      "HR": [ 
       { 
        "id": "7", "first_name": "David", "last_name": "Larry", "start_date": "1990-12-31", "end_date": "1998-02-12", "salary": "7897.78", "city": "New York", "description": "Manager", "department": "HR", "active": "1" 
       } 
      ] 
     } 
    } 
} 

由于这两个组都是JavaScript对象,你不” t需要“数”成员。您可以简单地使用数组的.length属性。使用javascript的for (var group in groups)语法循环组。

+1

这真的很有帮助,谢谢。 – WeaponX86

+0

一个不错的解决方案,稍后保存。 –

7

你可以看看从D3.js的nest()操作: https://github.com/mbostock/d3/blob/48ad44fdeef32b518c6271bb99a9aed376c1a1d6/src/arrays/nest.js 这是D3,较大的图书馆,但我只是链接到的代码快速寻找,我不认为这有任何的一部分依赖关系,所以你应该能够提取代码在这里用于你自己的项目。用法是described here in the docs - 您可以链接.key()方法来为嵌套结构的每个层定义键。在你的情况,这可能是这样的:

data = d3.nest() 
    .key(function(d) { return d.city }) 
    .key(function(d) { return d.description }) 
    .entries(data); 

结构这个吐出来是你有什么有点不同,而且它的功能非常相似:

[ 
    { 
    "key": "Toronto", 
    "values": [ 
     { 
     "key": "Programmer", 
     "values": [ 
      { 
      "active": "1", 
      "city": "Toronto", 
      "department": "Finance", 
      "description": "Programmer", 
      "end_date": "2006-07-25", 
      "first_name": "Jason", 
      "id": "1", 
      "last_name": "Martin", 
      "salary": "1234.56", 
      "start_date": "1996-07-25" 
      }, 
      // etc ... 
     ] 
     } 
    ] 
    }, 
    // etc ... 
] 
+0

+1好一个......对于我放在一起的快速和肮脏的版本有一些好处,包括;开发人员可选择的密钥(这意味着很容易使密钥不区分大小写或计算)以及排序。就个人而言,我可能会调整我的版本,以添加这些功能,而不是在(另一个)图书馆中输入...但很好找! – Steve

+1

谢谢 - 你不需要整个库,只是我链接到的代码中的函数,它没有任何D3依赖关系。但事实确实,这可能对某些项目来说过于夸张。 – nrabinowitz

+0

我一定会看看这个,很好找! – WeaponX86

0

大厦由@提供的示例nrabinowitz,这里是用经过收集和属性名作为参数的数组的最初提议的API巢功能,引擎盖下使用d3.nest:

function nest(data, keys) { 
    var nest = d3.nest(); 
    keys.forEach(function(k) { 
    nest.key(function(d) { 
     return d[k]; 
    }) 
    }); 
    return nest.entries(data); 
}