将平面对象数组转换为嵌套的对象数组

时间:2011-11-29 21:44:41

标签: javascript

原始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}
            ]
        }
    ]
}

我尝试编写一些递归函数,但是当我必须动态搜索树以避免重复时,它会一直卡住。

4 个答案:

答案 0 :(得分:10)

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

// 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对象,所以您不需要那个“count”成员。您可以简单地使用数组的.length属性。

使用javascript的for (var group in groups)语法遍历群组。

答案 1 :(得分: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 ...
]

答案 2 :(得分:0)

在@nrabinowitz提供的示例的基础上,这里是使用最初提议的API传递集合的nest函数和一个属性名称数组作为args,使用引擎盖下的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);
}

答案 3 :(得分:0)

使用https://www.npmjs.com/package/nesthydrationjs

const NestHydrationJS = require('nesthydrationjs')();
function getNestHydrationJS (results) {
  return  NestHydrationJS.nest(results);
}