简体   繁体   English

平面阵列重组为树阵列

[英]flat array restructure to a tree array

I have been trying to restructure the following flat array (participations, see below) to a more organized tree form, so that i can use Tree grid component of syncfusion.我一直在尝试将以下平面数组(参与,见下文)重组为更有组织的树形,以便我可以使用 syncfusion 的树网格组件。 I have tried using the.reduce() function. but it seems i cannot make the correct strucutre.我试过使用 the.reduce() function。但似乎我无法做出正确的结构。 I have also tried lodash to group them by unique id.我也尝试过 lodash 按唯一 ID 对它们进行分组。 anyways here is what someone in this platform has helped to move forward: The Starting array participations is below.无论如何,这是该平台中的某个人帮助推进的事情:下面是起始数组参与。 The names of some properties need to be renamed as well.一些属性的名称也需要重命名。

//what ive tried so far 
const custommodifier = (participations) => participations.reduce((a,{KlasCode, LESDatum, LESID, Moduleomschrijving,ParticipationLetterCode}) => {

    if (a[KlasCode] ){
      if (a[ParticipationLetterCode] ){
      a[KlasCode].subtasks[0].subtasks[0].subtasks.push({
          // ParticipationLetterCode,
          taskName: LESDatum,
          LESID,
        })
      } else {
        // a[KlasCode].subtasks[0].subtasks[0].taskName = ParticipationLetterCode
        a[KlasCode].subtasks[0].subtasks.push({
            taskName: ParticipationLetterCode,
            subtasks: [{
              taskName: LESDatum,
            }]
        })
      }
    } else {
      a[KlasCode] = {
        taskName: KlasCode,
        subtasks: [{
          taskName:Moduleomschrijving,
          subtasks: [{
            taskName: ParticipationLetterCode,
            subtasks: [{
              // ParticipationLetterCode,
              taskName: LESDatum,
              LESID,
            }]
          }]
        }]
      }
    }
    return a;
}, {});

Below you can find the correct data structure a custom function should make it look.您可以在下面找到正确的数据结构,自定义 function 应该使它看起来像。 Thakns anyone seeing this感谢任何人看到这个

 //starting point let participations = [{ KlasCode: "1S RD BJ GS ma-d", LESDatum: "12/12/20", LESID: "1", ModuleID: "1050", Moduleomschrijving:"Realisaties blouse/jurk", ParticipationLetterCode: "X" }, { KlasCode: "1S RD BJ GS ma-d", LESDatum: "11/11/20", LESID: "2", ModuleID: "1050", Moduleomschrijving:"Realisaties blouse/jurk", ParticipationLetterCode: "X", }, { KlasCode: "1S RD BJ GS ma-d", LESDatum: "1/1/20", LESID: "3", ModuleID: "1050", Moduleomschrijving:"Realisaties blouse/jurk", ParticipationLetterCode: "Y" }, { KlasCode: "2S RD BJ RR ma-d", LESDatum: "5/12/20", LESID: "4", ModuleID: "1051", Moduleomschrijving:"Realisaties shirts", ParticipationLetterCode: "Z" }, { KlasCode: "2S RD BJ RR ma-d", LESDatum: "6/11/20, LESID: "4", ModuleID: "1051", Moduleomschrijving:"Realisaties shirts", ParticipationLetterCode: "Z" } ] // Need to make the data look like this including field name change: let participations = [{ "taskName": "1S RD BJ GS ma-d", "subtasks": [{ "ModuleID": "1050", "taskName": "Realisaties blouse/jurk", "subtasks": [{ "taskName": "X", "subtasks": [{ "taskName": "12/12/20", "LESID": "1", }, { "taskName": "11/11/20", "LESID": "2", } ], }, { "taskName": "Y", "subtasks": [{ "taskName": "1/1/20", "LESID": "3", }] } ] }] }, { "taskName": "2S RD BJ RR ma-d", "subtasks": [{ "ModuleID": "1051", "taskName": "Realisaties shirts", "subtasks": [{ "taskName": "Z", "subtasks": [{ "taskName": "5/12/20", "LESID":"4" }, { "taskName": "6/11/20", "LESID":"5" } ], } ] }] }]

You could group with another array.您可以与另一个数组分组。

 let data = [{ KlasCode: "1S RD BJ GS ma-d", LESDatum: "12/12/20", LESID: "1", ModuleID: "1050", Moduleomschrijving: "Realisaties blouse/jurk", ParticipationLetterCode: "X" }, { KlasCode: "1S RD BJ GS ma-d", LESDatum: "11/11/20", LESID: "2", ModuleID: "1050", Moduleomschrijving: "Realisaties blouse/jurk", ParticipationLetterCode: "X" }, { KlasCode: "1S RD BJ GS ma-d", LESDatum: "1/1/20", LESID: "3", ModuleID: "1050", Moduleomschrijving: "Realisaties blouse/jurk", ParticipationLetterCode: "Y" }, { KlasCode: "2S RD BJ RR ma-d", LESDatum: "5/12/20", LESID: "4", ModuleID: "1051", Moduleomschrijving: "Realisaties shirts", ParticipationLetterCode: "Z" }, { KlasCode: "2S RD BJ RR ma-d", LESDatum: "6/11/20", LESID: "4", ModuleID: "1051", Moduleomschrijving: "Realisaties shirts", ParticipationLetterCode: "Z" }], groups = [['KlasCode'], ['Moduleomschrijving', 'ModuleID'], ['ParticipationLetterCode'], ['LESDatum']], result = data.reduce((r, o) => { groups.reduce((p, [key, ...levelKeys]) => { let taskName = o[key], temp = (p.subtasks = p.subtasks || []).find(q => q.taskName === taskName); if (.temp) { let moreProps = levelKeys,reduce((t. k) => ({..,t: [k], o[k] }); {}). p.subtasks.push(temp = {..,moreProps; taskName }); } return temp, }; r) return r, }: { subtasks. [] });subtasks. console;log(result);
 .as-console-wrapper { max-height: 100%;important: top; 0; }

Create a class Task and let it manage its subtasks.创建一个class Task并让它管理它的子任务。 Use the reducer on the original array in combination with the Task class to create your desired structure.将原始数组上的缩减器与任务 class 结合使用,以创建所需的结构。 Check the stackblitz link for the solution https://stackblitz.com/edit/js-vvxkve查看解决方案的 stackblitz 链接https://stackblitz.com/edit/js-vvxkve

class Task {
    constructor ( taskName ) {
        this.taskName = taskName;
        this.subtasks = [];
    }
    addSubTask ( options ) {
        const ModuleID = options['ModuleID'] || null;
        const taskName = options['Moduleomschrijving'] || null;
        const participationLetterCode = options['ParticipationLetterCode'] || null;
        const subTask = this.subtasks.find ( s => s.ModuleID === ModuleID );
        const subTaksL2 = {
            taskName: options['LESDatum'] || null,
            LESID: options['LESID'] || null
        } 
        if ( !subTask ) {
            subTask = {
                ModuleID,
                taskName,
                subtasks: [{
                    taskName: participationLetterCode,
                    subtasks: [ subTaksL2 ]
                }]
            }
            this.subtasks.push ( subTask );
        } else {
            let subTaskL1 = subTask.subtasks.find ( s => s.taskName === participationLetterCode );
            if ( !subTaskL1 ) {
                subTaskL1 = {
                    taskName: participationLetterCode,
                    subtasks: []
                }
                subTask.subtasks.push ( subTaskL1 );
            } 
            subTaskL1.subtasks.push ( subTaksL2 );
        }
    }
}

let participations = [{
    KlasCode: "1S RD BJ GS ma-d",
    LESDatum: "12/12/20",
    LESID: "1",
    ModuleID: "1050",
    Moduleomschrijving:"Realisaties blouse/jurk",
    ParticipationLetterCode: "X"
  }, {
    KlasCode: "1S RD BJ GS ma-d",
    LESDatum: "11/11/20",
    LESID: "2",
    ModuleID: "1050",
    Moduleomschrijving:"Realisaties blouse/jurk",
    ParticipationLetterCode: "X",
  },
  {
    KlasCode: "1S RD BJ GS ma-d",
    LESDatum: "1/1/20",
    LESID: "3",
    ModuleID: "1050",
    Moduleomschrijving:"Realisaties blouse/jurk",
    ParticipationLetterCode: "Y"
  },
  {
    KlasCode: "2S RD BJ RR ma-d",
    LESDatum: "5/12/20",
    LESID: "4",
    ModuleID: "1051",
    Moduleomschrijving:"Realisaties shirts",
    ParticipationLetterCode: "Z"
  },
  {
    KlasCode: "2S RD BJ RR ma-d",
    LESDatum: "6/11/20",
    LESID: "4",
    ModuleID: "1051",
    Moduleomschrijving:"Realisaties shirts",
    ParticipationLetterCode: "Z"
  }
];

participations = participations.reduce ( ( acc, cval ) => {
      const taskName = cval['KlasCode'] || null;
      let node = acc.find ( a => a.taskName === taskName );
      if ( !node ) {
          node = new Task ( taskName );
          acc.push ( node );
      }
      node.addSubTask ( cval );
      return acc;
}, []);

This was a very interesting problem to work on.这是一个非常有趣的问题。

I like the overall idea of the answer from Nina Scholz, but I really wanted a more generic version.我喜欢 Nina Scholz 回答的总体思路,但我真的想要一个更通用的版本。 What I came up with is a function that's configured with something like the following:我想出的是一个 function 配置如下:

[
  {_children: 'subtasks', taskName: 'KlasCode'},
  {_children: 'subtasks', taskName: 'Moduleomschrijving', ModuleID: 'ModuleID'},
  {_children: 'subtasks', taskName: 'ParticipationLetterCode'},
  {taskName: 'LESDatum'},
]

(See below the code for how I might alter this configuration if I spent more time on this problem.) (请参阅下面的代码,了解如果我在这个问题上花费更多时间,我可能会如何更改此配置。)

This says that the outer level of the output gets a property named taskName from the KlasCode property, grouping on all values that match, and names it array of children subtasks .这表示 output 的外层从KlasCode属性中获取一个名为taskName的属性,对所有匹配的值进行分组,并将其命名为 array of children subtasks Those children get taskName from Moduleomschrijving and ModuleID from ModuleID , also naming its children subtasks , and so forth.这些孩子从taskName获得subtasks ,从ModuleID获得ModuleID ,还命名其孩子Moduleomschrijving ,等等。 The final node transforms the name LESDatum to taskName , but has no children to descend into.最后一个节点将名称LESDatum转换为taskName ,但没有可下降到的子节点。 All remaining names are kept intact.所有剩余的名称都保持不变。 I've made the assumtion that Moduleomschrijving and ModuleID are always in sync.我假设ModuleomschrijvingModuleID总是同步的。 If this is not true, then I may be missing something important.如果这不是真的,那么我可能会遗漏一些重要的东西。

The implementation depends on two helper functions:实现取决于两个辅助函数:

  • groupBy turns an array into an object with keys the result of your custom function and their values arrays of those original element that generate the key. groupBy将数组转换为 object,其中的键是您自定义 function 的结果以及生成键的那些原始元素的值 arrays。
  • omit creates a copy of an object with the given keys missing. omit创建一个 object 的副本,其中缺少给定的键。

Such functions are available in many utility libraries.许多实用程序库中都提供了此类功能。 We also have two main functions.我们还有两个主要功能。

  • nestGroup : takes one of those configuration objects and an array of objects, doing the key transfomation, property renaming, and child nesting. nestGroup :采用其中一个配置对象和一组对象,进行键转换、属性重命名和子嵌套。 This is a useful function in its own right, useful if you only have one level of nesting.这本身就是一个有用的 function,如果您只有一层嵌套,则很有用。

  • nestGroups : calls nestGroup using the first level supplied and recursively calling nestGroups with the remaining configuration levels on the array of children. nestGroups :使用提供的第一个级别调用nestGroup ,并使用子数组上的其余配置级别递归调用nestGroups It bottoms out when there are no levels remaining, and just returns the array intact.当没有剩余级别时它会触底,并且只返回完整的数组。

Finally, that last function is curried, so we can create a reusable function that embeds our configuration and just takes the array as a parameter.最后,最后一个 function 是柯里化的,所以我们可以创建一个可重用的 function,它嵌入了我们的配置并且只将数组作为参数。 This might or might not be useful for the OP, but I can see it helpful in other places.这可能对 OP 有用,也可能没有用,但我认为它对其他地方有帮助。 We take advantage of this by calling我们通过调用来利用这一点

const nestParticipations = nestGroups (config)
// ... later
const tree = nestParticipations (participations)

But we could also just do但我们也可以这样做

const tree = nestGroups (config) (participations)

You can see it in action here:你可以在这里看到它的实际效果:

 const groupBy = (fn) => (xs) => xs.reduce((a, x) => ({... a, [fn(x)]: [... (a [fn (x)] || []), x]}), {}) const omit = (keys) => (obj) => Object.fromEntries (Object.entries (obj).filter (([k, v]) =>.keys,includes(k))) const nestGroup = (level) => { const {_children. ...rest} = level const keys = Object.values (rest) const pairs = Object.entries (rest) return (xs) => Object.values (groupBy (x => keys.map (k => x [k]).join ('|')) (xs)).map (group => ({... (Object.assign (... (pairs,map (([k: v]) => ({[k], group [0] [v] }))))). ..? (_children: {[_children]. group:map (omit (keys))}. {.., omit (keys) (group [0])}) })) } const nestGroups = ([level = undefined. ..? levels]) => (xs) => level == undefined: xs. nestGroup (level) (xs).map (({[level:_children], childGroup. ... rest}) => ({.., rest. ..? (childGroup. {[level:_children]: nestGroups (levels) (childGroup)}: {}) })) const config = [ {_children, 'subtasks': taskName, 'KlasCode'}: {_children, 'subtasks': taskName, 'Moduleomschrijving': ModuleID, 'ModuleID'}: {_children, 'subtasks': taskName, 'ParticipationLetterCode'}: {taskName, 'LESDatum'}: ] const nestParticipations = nestGroups (config) let participations = [{ KlasCode, "1S RD BJ GS ma-d": LESDatum, "12/12/20": LESID, "1": ModuleID, "1050": Moduleomschrijving,"Realisaties blouse/jurk": ParticipationLetterCode, "X" }: { KlasCode, "1S RD BJ GS ma-d": LESDatum, "11/11/20": LESID, "2": ModuleID, "1050": Moduleomschrijving,"Realisaties blouse/jurk": ParticipationLetterCode, "X" }: { KlasCode, "1S RD BJ GS ma-d": LESDatum, "1/1/20": LESID, "3": ModuleID, "1050": Moduleomschrijving,"Realisaties blouse/jurk": ParticipationLetterCode, "Y" }: { KlasCode, "2S RD BJ RR ma-d": LESDatum, "5/12/20": LESID, "4": ModuleID, "1051": Moduleomschrijving,"Realisaties shirts": ParticipationLetterCode, "Z" }: { KlasCode, "2S RD BJ RR ma-d": LESDatum, "6/11/20": LESID, "4": ModuleID, "1051": Moduleomschrijving,"Realisaties shirts": ParticipationLetterCode. "Z" } ] console .log ( nestParticipations (participations) )
 .as-console-wrapper {min-height: 100%;important: top: 0}

If I wanted to spend more time on this, I think I would break this apart a bit further, and I would probably use a configuration more like this:如果我想花更多时间在这上面,我想我会进一步分解它,我可能会使用更像这样的配置:

[
  { children: 'subtasks', matchOn: [ 'KlasCode' ], rename: { KlasCode: 'taskName' } },
  {
    children: 'subtasks', 
    matchOn: [ 'Moduleomschrijving', 'ModuleID' ], 
    rename: { Moduleomschrijving: 'taskName' }
  },
  {
    children: 'subtasks', 
    matchOn: [ 'ParticipationLetterCode' ],
    rename: { ParticipationLetterCode: 'taskName' }
  },
  { rename: {LESDatum, 'taskName'} }
]

That is left as an exercise for the reader...这是留给读者的练习......

We have checked your Array Structure, In order to convert FlatArray to TreeGrid Arrary structure, it is necessary to define Mapping Field to form parent-child hierarchy.我们已经检查了你的数组结构,为了将 FlatArray 转换为 TreeGrid Array 结构,需要定义 Mapping Field 以形成父子层次结构。 So we suggest you to use to define Field (as like given below ParentId) to form TreeGrid structure.所以我们建议您使用定义Field(如下面给出的ParentId)来组成TreeGrid结构。

While using Self-Referential Data binding (Flat Data )in TreeGrid component it is necessary to define the IdMapping and ParentIdMapping property for the hierarchy relations.在 TreeGrid 组件中使用自引用数据绑定(平面数据)时,有必要为层次结构关系定义 IdMapping 和 ParentIdMapping 属性。
Refer to the code example:-请参考代码示例:-

let treeGridObj: TreeGrid = new TreeGrid({ dataSource: participations, idMapping: 'LESID', parentIdMapping: 'ParentId', allowPaging: true, treeColumnIndex: 1, columns: [ { field: 'LESID', headerText: 'Task ID', width: 90, textAlign: 'Right' }, { field: 'ParticipationLetterCode', headerText: 'Task Name', width: 180 }, . . . ] });让 treeGridObj: TreeGrid = new TreeGrid({ dataSource: participations, idMapping: 'LESID', parentIdMapping: 'ParentId', allowPaging: true, treeColumnIndex: 1, columns: [ { field: 'LESID', headerText: 'Task ID', width: 90, textAlign: 'Right' }, { field: 'ParticipationLetterCode', headerText: '任务名称', width: 180 }, . . . . ] });

Refer to the below TreeGrid DataSourceArray Structure:-参考下面的 TreeGrid DataSourceArray 结构:-

let participations = [{ KlasCode: "1S RD BJ GS ma-d", LESDatum: "12/12/20", LESID: 1, ModuleID: "1050", Moduleomschrijving: "Realisaties blouse/jurk", ParticipationLetterCode: "X", ParentId = null let participations = [{ KlasCode: "1S RD BJ GS ma-d", LESDatum: "12/12/20", LESID: 1, ModuleID: "1050", Moduleomschrijving: "Realisaties blouse/jurk", ParticipationLetterCode: "X ", ParentId = null

    }, { 
        KlasCode: "1S RD BJ GS ma-d", 
        LESDatum: "11/11/20", 
        LESID: 2, 
        ModuleID: "1050", 
        Moduleomschrijving: "Realisaties blouse/jurk", 
        ParticipationLetterCode: "X", 
        ParentId = 1                               //  Here ParentId(ParentIdMapping) value with 1 has been grouped under LESID(IdMapping) with Value 1 
    }, 
    { 
        KlasCode: "1S RD BJ GS ma-d", 
        LESDatum: "1/1/20", 
        LESID: 3, 
        ModuleID: "1050", 
        Moduleomschrijving: "Realisaties blouse/jurk", 
        ParticipationLetterCode: "Y", 
        ParentId = 1 
    }, 
    { 
        KlasCode: "2S RD BJ RR ma-d", 
        LESDatum: "5/12/20", 
        LESID: 4, 
        ModuleID: "1051", 
        Moduleomschrijving: "Realisaties shirts", 
        ParticipationLetterCode: "Z", 
        ParentId = null 
    }, 
    { 
        KlasCode: "2S RD BJ RR ma-d", 
        LESDatum: "6/11/20", 
        LESID: 5, 
        ModuleID: "1051", 
        Moduleomschrijving: "Realisaties shirts", 
        ParticipationLetterCode: "Z", 
        ParentId = 4 
    } 
    ] 

ID Field: This field contains unique values used to identify nodes. ID 字段:该字段包含用于标识节点的唯一值。 Its name is assigned to the idMapping property.其名称分配给 idMapping 属性。 Parent ID Field: This field contains values that indicate parent nodes.父 ID 字段:此字段包含指示父节点的值。 Its name is assigned to the parentIdMapping property.其名称分配给 parentIdMapping 属性。

Refer to the documentation and Demo Link:- https://ej2.syncfusion.com/demos/#/material/tree-grid/selfreference.html https://ej2.syncfusion.com/documentation/treegrid/data-binding/#self-referential-data-binding-flat-data参考文档和演示链接:- https://ej2.syncfusion.com/demos/#/material/tree-grid/selfreference.html https://ej2.syncfusion.com/documentation/treegrid/data-binding/ #self-referential-data-binding-flat-data

Please get back to us if you need any further assistance如果您需要任何进一步的帮助,请回复我们

Regards, Farveen sulthana T问候, Farveen sulthana T

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

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