【问题标题】:Javascript created nested object from flat objectJavascript从平面对象创建嵌套对象
【发布时间】:2017-05-15 20:26:58
【问题描述】:

我正在尝试创建一个层次结构,以便我可以将数据传递给我用来生成组织结构图的插件。

对于我的组织结构图,我拥有我需要处理的所有数据,例如员工和一些关于他们的基本数据。

FirstName
LastName
EmployeeID
ManagerEmployeeID
Manager Name

这些数据存储在一个数组中,不同级别之间没有嵌套或链接,这是我试图用一些 jquery/javascript 来实现的。

我的目标是获取这个数组并根据ManagerID 和EmployeeID 嵌套它,这样我就可以创建一个树层次结构。

我无法更改向我提供数据的方式,否则我会将其从数据库响应中嵌套。

示例数据:

•   Tom Jones
   o    Alice Wong
   o    Tommy J.
•   Billy Bob
   o    Rik A.
     ♣  Bob Small
     ♣  Small Jones
   o    Eric C.

我的平面数据示例:

    {
        "FirstName": "Tom"
        "LastName": "Jones"
        "EmployeeID": "123"
        "ManagerEmployeeID": ""
        "Manager Name": ""
    },
    {
        "FirstName": "Alice"
        "LastName": "Wong"
        "EmployeeID": "456"
        "ManagerEmployeeID": "123"
        "Manager Name": "Tom Jones"
    },
    {
        "FirstName": "Tommy"
        "LastName": "J."
        "EmployeeID": "654"
        "ManagerEmployeeID": "123"
        "Manager Name": "Tom Jones"
    },
    {
        "FirstName": "Billy"
        "LastName": "Bob"
        "EmployeeID": "777"
        "ManagerEmployeeID": ""
        "Manager Name": ""
    },
    {
        "FirstName": "Rik"
        "LastName": "A."
        "EmployeeID": "622"
        "ManagerEmployeeID": "777"
        "Manager Name": "Billy Bob"
    },
    {
        "FirstName": "Bob"
        "LastName": "Small"
        "EmployeeID": "111"
        "ManagerEmployeeID": "622"
        "Manager Name": "Rik A."
    },
    {
        "FirstName": "Small"
        "LastName": "Jones"
        "EmployeeID": "098"
        "ManagerEmployeeID": "622"
        "Manager Name": "Rik A"
    },
    {
        "FirstName": "Eric"
        "LastName": "C."
        "EmployeeID": "222"
        "ManagerEmployeeID": "777"
        "Manager Name": "Billy Bob"
    }

所需输出示例:

{
    "FirstName": "Tom",
    "LastName": "Jones",
    "EmployeeID": "123",
    "ManagerEmployeeID": "",
    "Manager Name": "",
    {
        "FirstName": "Alice",
        "LastName": "Wong",
        "EmployeeID": "456",
        "ManagerEmployeeID": "123",
        "Manager Name": "Tom Jones",

    },
    {
        "FirstName": "Tommy",
        "LastName": "J.",
        "EmployeeID": "654",
        "ManagerEmployeeID": "123",
        "Manager Name": "Tom Jones",

    },

},
{
    "FirstName": "Billy",
    "LastName": "Bob",
    "EmployeeID": "777",
    "ManagerEmployeeID": "",
    "Manager Name": "",
    {
        "FirstName": "Rik",
        "LastName": "A.",
        "EmployeeID": "622",
        "ManagerEmployeeID": "777",
        "Manager Name": "Billy Bob",
        ,
        {
            "FirstName": "Bob",
            "LastName": "Small",
            "EmployeeID": "111",
            "ManagerEmployeeID": "622",
            "Manager Name": "Rik A.",

        },
        {
            "FirstName": "Small",
            "LastName": "Jones",
            "EmployeeID": "098",
            "ManagerEmployeeID": "622",
            "Manager Name": "Rik A",

        },

    },

},
{
    "FirstName": "Eric",
    "LastName": "C.",
    "EmployeeID": "222",
    "ManagerEmployeeID": "777",
    "Manager Name": "Billy Bob",

}

是否有任何最佳实践来完成这样的事情?如果我有能力在数据库级别做到这一点,我会的。但是,我只有一个数据列表以及基于 ID 的经理和员工之间的相关性。

【问题讨论】:

    标签: javascript jquery arrays json


    【解决方案1】:

    您可以使用reduce() 创建递归函数,这将返回所需的数据结构。

    var data = [{"FirstName":"Tom","LastName":"Jones","EmployeeID":"123","ManagerEmployeeID":"","Manager Name":""},{"FirstName":"Alice","LastName":"Wong","EmployeeID":"456","ManagerEmployeeID":"123","Manager Name":"Tom Jones"},{"FirstName":"Tommy","LastName":"J.","EmployeeID":"654","ManagerEmployeeID":"123","Manager Name":"Tom Jones"},{"FirstName":"Billy","LastName":"Bob","EmployeeID":"777","ManagerEmployeeID":"","Manager Name":""},{"FirstName":"Rik","LastName":"A.","EmployeeID":"622","ManagerEmployeeID":"777","Manager Name":"Billy Bob"},{"FirstName":"Bob","LastName":"Small","EmployeeID":"111","ManagerEmployeeID":"622","Manager Name":"Rik A."},{"FirstName":"Small","LastName":"Jones","EmployeeID":"098","ManagerEmployeeID":"622","Manager Name":"Rik A"},{"FirstName":"Eric","LastName":"C.","EmployeeID":"222","ManagerEmployeeID":"777","Manager Name":"Billy Bob"}];
    
    function makeTree(data, parentId) {
      return data.reduce(function(r, e) {
        if (e.ManagerEmployeeID == parentId) {
          var employees = makeTree(data, e.EmployeeID);
          if (employees.length) e.employees = employees
          r.push(e)
        }
        return r;
      }, [])
    }
    
    console.log(makeTree(data, ''))

    【讨论】:

    • 谢谢,现在正在努力整合它。由于某种原因,它抛出了`TypeError: data.reduce is not a function`。
    • 是data 数组吗?
    • 显然是一个对象数组。 (oi63.tinypic.com/2ivd2rt.jpg)。抱歉,我写出来的时候没有注意到,我的开发环境落后了几个版本。
    • 只用这段代码运行函数,看看你是否收到错误jsfiddle.net/Lg0wyt9u/1907
    • 这返回了一个空数组 []
    【解决方案2】:

    所需的输出不是 javascript 的有效数据结构。您需要该对象中的一些键来指向“孩子”。对于解决方案 - 通常您遍历整个对象,将 ID 保存为对象中的键,其余部分作为给定 ID 的值。例如

    let tree = {}
    flat.forEach(function(item) {
      item.children = [];
      tree[item.id] = item // build whole tree 
    
      // in case it is ordered by parent, you can use
      tree[item.parentId].children.push(item);
    })
    // in case it is not ordered, you have to traverse the structure again
    flat.forEach(function(item) {
      tree[item.parentId].children.push(item);
    })
    

    【讨论】:

      【解决方案3】:

      您可以使用单循环方法并检查父母,也就是 ManagerEmployeeID 和孩子。

      此提议也适用于未排序的数据,无需递归。

      var data = [{ FirstName: "Tom", LastName: "Jones", EmployeeID: "123", ManagerEmployeeID: "", "Manager Name": "" }, { FirstName: "Alice", LastName: "Wong", EmployeeID: "456", ManagerEmployeeID: "123", "Manager Name": "Tom Jones" }, { FirstName: "Tommy", LastName: "J.", EmployeeID: "654", ManagerEmployeeID: "123", "Manager Name": "Tom Jones" }, { FirstName: "Billy", LastName: "Bob", EmployeeID: "777", ManagerEmployeeID: "", "Manager Name": "" }, { FirstName: "Rik", LastName: "A.", EmployeeID: "622", ManagerEmployeeID: "777", "Manager Name": "Billy Bob" }, { FirstName: "Bob", LastName: "Small", EmployeeID: "111", ManagerEmployeeID: "622", "Manager Name": "Rik A." }, { FirstName: "Small", LastName: "Jones", EmployeeID: "098", ManagerEmployeeID: "622", "Manager Name": "Rik A" }, { FirstName: "Eric", LastName: "C.", EmployeeID: "222", ManagerEmployeeID: "777", "Manager Name": "Billy Bob" }],
          tree = function (data, root) {
              var r = [],
                  o = {};
      
              data.forEach(function (a) {
                  a.children = o[a.EmployeeID] && o[a.EmployeeID].children;
                  o[a.EmployeeID] = a;
                  if (a.ManagerEmployeeID === root) {
                      r.push(a);
                  } else {
                      o[a.ManagerEmployeeID] = o[a.ManagerEmployeeID] || {};
                      o[a.ManagerEmployeeID].children = o[a.ManagerEmployeeID].children || [];
                      o[a.ManagerEmployeeID].children.push(a);
                  }
              });
              return r;
          }(data, '');
      
      console.log(tree);
      .as-console-wrapper { max-height: 100% !important; top: 0; }

      问题是,您需要指定root,在本例中为MgrQID: "5555",其中"5555" 是调用函数的根值

      tree = function (data, root) {
          // code
      }(data, "5555");
      //      ^^^^^^
      

      var data = [{ QID: "1234", MgrQID: "5555", PositionTitle: "Manager, Systems Administration 3" }, { QID:"5678", MgrQID: "1234", PositionTitle: "Systems Administrator 3" }],
          tree = function (data, root) {
              var r = [],
                  o = {};
      
              data.forEach(function (a) {
                  a.children = o[a.QID] && o[a.QID].children;
                  o[a.QID] = a;
                  if (a.MgrQID === root) {
                      r.push(a);
                  } else {
                      o[a.MgrQID] = o[a.MgrQID] || {};
                      o[a.MgrQID].children = o[a.MgrQID].children || [];
                      o[a.MgrQID].children.push(a);
                  }
              });
              return r;
          }(data, "5555");
      
      console.log(tree);
      .as-console-wrapper { max-height: 100% !important; top: 0; }

      【讨论】:

      • 我试了一下,但我的数组是空的。在这个例子中,我尝试了两名员工。经理和向他们汇报的人(员工)。 jsfiddle.net/pqncv5ny
      【解决方案4】:

      您可以使用breadth-first search 在树中查找父员工并对其员工进行插入。

      尝试如下。

      const data = [{"FirstName":"Tom","LastName":"Jones","EmployeeID":"123","ManagerEmployeeID":"","Manager Name":""},{"FirstName":"Alice","LastName":"Wong","EmployeeID":"456","ManagerEmployeeID":"123","Manager Name":"Tom Jones"},{"FirstName":"Tommy","LastName":"J.","EmployeeID":"654","ManagerEmployeeID":"123","Manager Name":"Tom Jones"},{"FirstName":"Billy","LastName":"Bob","EmployeeID":"777","ManagerEmployeeID":"","Manager Name":""},{"FirstName":"Rik","LastName":"A.","EmployeeID":"622","ManagerEmployeeID":"777","Manager Name":"Billy Bob"},{"FirstName":"Bob","LastName":"Small","EmployeeID":"111","ManagerEmployeeID":"622","Manager Name":"Rik A."},{"FirstName":"Small","LastName":"Jones","EmployeeID":"098","ManagerEmployeeID":"622","Manager Name":"Rik A"},{"FirstName":"Eric","LastName":"C.","EmployeeID":"222","ManagerEmployeeID":"777","Manager Name":"Billy Bob"}];
      
      const nestedObj = {
        employees: [],
      };
      
      // if found the parent then append it and return true, otherwise return false
      const findParentAndAppendChild = (ID, obj, employee) => {
        if (obj.EmployeeID === ID) {
          // parent is obj, add child into its children
          obj.employees ? obj.employees.push(employee) : (obj.employees = [employee]);
          // indication to stop search further (check loop in else block using Array.some method)
          return true;
        } else {
          const foundParet =
            obj.employees &&
            obj.employees.some((childObj) =>
              findParentAndAppendChild(ID, childObj, employee)
            );
          return foundParet ? true : false;
        }
      };
      
      data.forEach((employee) => {
        if (employee.ManagerEmployeeID === "") {
          // top level employee
          nestedObj.employees.push(employee);
        } else {
          // non top level employee 
          findParentAndAppendChild(employee.ManagerEmployeeID, nestedObj, employee);
        }
      });
      
      // log the output
      console.log(JSON.stringify(nestedObj.employees, null, 2));

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-10-06
        • 1970-01-01
        • 1970-01-01
        • 2017-02-14
        • 1970-01-01
        • 2018-09-30
        相关资源
        最近更新 更多