简体   繁体   English

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

[英]Convert flat array of objects into nested array of objects

Original JSON data (flat table):原始 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"}
]

I need to call the function like this:我需要像这样调用函数:

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

The first parameter is the entire dataset, the second is an array of columns which define the nesting level.第一个参数是整个数据集,第二个参数是定义嵌套级别的列数组。

Expected JSON output:预期的 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}
            ]
        }
    ]
}

] ]

I've tried writing a few recursive functions but keep getting stuck when I have to dynamically search the tree to avoid duplication.我已经尝试编写一些递归函数,但是当我必须动态搜索树以避免重复时一直卡住。

Thought this was a fun little question, so I did it... but, I do agree with the people who asked "what have you tried so far".认为这是一个有趣的小问题,所以我做了……但是,我同意那些问“到目前为止你尝试过什么”的人。 Typically, you should talk about a specific problem.通常,您应该谈论一个特定的问题。

// 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;
}

Call the method like this:像这样调用方法:

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

The output from this method for your data looks like this:此方法的数据输出如下所示:

{
    "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"
                }
            ]
        }
    }
}

Because the groups are all javascript objects, you don't need that "count" member.因为这些组都是 javascript 对象,所以您不需要那个“计数”成员。 You can simply use the .length property of the array(s).您可以简单地使用数组的 .length 属性。

Loop through the groups using javascript's for (var group in groups) syntax.使用 javascript 的for (var group in groups)语法循环遍历组。

You might take a look at the nest() operator from D3.js: https://github.com/mbostock/d3/blob/48ad44fdeef32b518c6271bb99a9aed376c1a1d6/src/arrays/nest.js This is part of D3, a larger library, but looking quickly at the code I just linked to, I don't think this has any dependencies, so you should be able to lift the code here for use in your own project.你可以看看 D3.js 中的nest()操作符: https : //github.com/mbostock/d3/blob/48ad44fdeef32b518c6271bb99a9aed376c1a1d6/src/arrays/nest.js这是 D3 的一部分,一个更大的库,但是快速查看我刚刚链接到的代码,我认为这没有任何依赖关系,因此您应该能够在此处提取代码以在您自己的项目中使用。 Usage is described here in the docs - you chain .key() methods to define the keys for each layer of the nested structure.文档中描述了用法 - 您链接.key()方法来定义嵌套结构的每一层的键。 In your case, this might look like:在您的情况下,这可能如下所示:

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

The structure this spits out is a little different from what you have, but it's functionally quite similar:这吐出的结构与您拥有的结构略有不同,但在功能上非常相似:

[
  {
    "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 ...
]

Building on the example provided by @nrabinowitz, here's the nest function with the originally proposed API of passing the collection and an array of property names as args, using d3.nest under the hood:在@nrabinowitz 提供的示例的基础上,这里的 nest 函数具有最初提出的 API 传递集合和属性名称数组作为 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);
}

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM