简体   繁体   English

将数组从平面一维转换为树,如 javascript/lodash

[英]transform an array from a flat 1 dimensional to a tree like in javascript/lodash

i having trouble to transform the following array data1 to look like data2:I tried to use lodash but its a bit strange _gropuby gives me an object array.我无法将以下数组 data1 转换为看起来像 data2:我尝试使用 lodash 但它有点奇怪 _gropuby 给了我一个 object 数组。 Should i be looping inside the array...creating a custom function for this.我应该在数组内部循环...为此创建一个自定义 function 。 or is there a trick in lodash to simplify this.或者 lodash 中是否有一个技巧来简化这一点。 Thankssss /********************************************************************************************谢谢 /****************************************************** ************************************************

 let data1 = [{ KlasCode: "AA", LESDatum: "06/02/2017", LESID: "1", ModuleID: "1061", ParticipationLetterCode: "Y" }, { KlasCode: "AA", LESDatum: "07/02/2017", LESID: "2", ModuleID: "1061", ParticipationLetterCode: "X", }, { KlasCode: "AA", LESDatum: "13/02/2017", LESID: "3", ModuleID: "1062", ParticipationLetterCode: "Z" }, { KlasCode: "BB", LESDatum: "16/02/2017", LESID: "4", ModuleID: "1063", ParticipationLetterCode: "X" } ] //The output should be like a tree array system, something more organized such as the following code: let data2 = [{ KlasCode: "AA", Modules: [ { ModuleID: "1061", Participation: [{ ParticipationLetterCode: "Y", LESDatum: "06/02/2017", LESID: "1" }, { ParticipationLetterCode: "X", LESDatum: "07/02/2017", LESID: "2" } }, { ModuleID: "1062", Participation:[{ ParticipationLetterCode: "Z", LESDatum: "13/02/2017", LESID: "3" }] } }] }, { KlasCode: "BB", Modules: [{ ModuleID: "1063", Participation: [{ ParticipationLetterCode: "x", LESDatum: "6/02/2017", LESID: "4" }] }] } ]

Created a function to do the same, hope this helps -:创建了一个 function 来做同样的事情,希望这会有所帮助-:

 const custommodifier = (data) => Object.values(data.reduce((acc,{KlasCode, ModuleID, ...participationData}) => { if(acc[KlasCode]){ acc[KlasCode].Modules[0].Participation.push({...participationData }) } else { acc[KlasCode] = { KlasCode, Modules: [{ ModuleID, Participation: [{...participationData }] }] } } return acc; }, {})); let data = [{ KlasCode: "AA", LESDatum: "06/02/2017", LESID: "1", ModuleID: "1061", ParticipationLetterCode: "Y" }, { KlasCode: "AA", LESDatum: "07/02/2017", LESID: "2", ModuleID: "1061", ParticipationLetterCode: "X", }, { KlasCode: "AA", LESDatum: "13/02/2017", LESID: "3", ModuleID: "1061", ParticipationLetterCode: "Z" }, { KlasCode: "BB", LESDatum: "16/02/2017", LESID: "4", ModuleID: "1062", ParticipationLetterCode: "X" } ] console.log(custommodifier(data))

You could take a dynamic approach with an array of keys ad group names and take the keys out of the actual object.您可以对一组键广告组名称采取动态方法,并从实际的 object 中取出键。 At the end, after building nested groups, add the final object to the last group.最后,在构建嵌套组后,将最终的 object 添加到最后一个组。

This approach works for more nested groups if necessary.如有必要,此方法适用于更多嵌套组。

 let data = [{ KlasCode: "AA", LESDatum: "06/02/2017", LESID: "1", ModuleID: "1061", ParticipationLetterCode: "Y" }, { KlasCode: "AA", LESDatum: "07/02/2017", LESID: "2", ModuleID: "1061", ParticipationLetterCode: "X" }, { KlasCode: "AA", LESDatum: "13/02/2017", LESID: "3", ModuleID: "1061", ParticipationLetterCode: "Z" }, { KlasCode: "BB", LESDatum: "16/02/2017", LESID: "4", ModuleID: "1062", ParticipationLetterCode: "X" }], groups = [['KlasCode', 'Modules'], ['ModuleID', 'Participation']], result = data.reduce((r, o) => { groups.reduce((p, [key, group]) => { let value, temp; ({ [key]: value, ...o } = o); temp = p.find(q => q[key] === value); if (.temp) p:push(temp = { [key], value: [group]; [] }); return temp[group], }. r);push(o); return r, }; []). console;log(result);
 .as-console-wrapper { max-height: 100%;important: top; 0; }

I would use a groupBy function in conjunction with a little fiddling with Object.entries .我会使用groupBy function 和Object.entries的一点点摆弄。 You will need to use it twice, to handle your two levels of grouping.您将需要使用它两次,以处理您的两个级别的分组。

You could use the groupBy from lodash (or the one from Ramda, or wherever), or the simple one included here.您可以使用来自groupBy的 groupBy(或者来自 Ramda 的那个,或者其他任何地方),或者这里包含的简单的那个。

 const groupBy = (fn) => (xs) => xs.reduce((a, x) => ({... a, [fn(x)]: [... (a [fn (x)] || []), x]}), {}) const transform = (data) => Object.entries (groupBy (x => x.KlasCode) (data)).map(([KlasCode, Modules]) => ({ KlasCode, Modules: Object.entries(groupBy (x => x.ModuleID) (Modules)).map(([ModuleID, Participations]) => ({ ModuleID, Participation: Participations.map (({ParticipationLetterCode, KlasCode, ...rest}) => rest) }) ) })) let data1 = [{KlasCode: "AA", LESDatum: "06/02/2017", LESID: "1", ModuleID: "1061", ParticipationLetterCode: "Y"}, {KlasCode: "AA", LESDatum: "07/02/2017", LESID: "2", ModuleID: "1061", ParticipationLetterCode: "X"}, {KlasCode: "AA", LESDatum: "13/02/2017", LESID: "3", ModuleID: "1062", ParticipationLetterCode: "Z"}, {KlasCode: "BB", LESDatum: "16/02/2017", LESID: "4", ModuleID: "1063", ParticipationLetterCode: "X"}] console.log (transform (data1))
 .as-console-wrapper {min-height: 100%;important: top: 0}

Update -- a Ramda alternative更新——Ramda 的替代品

I wasn't thrilled by the above solution, nor by the other answers here.我对上述解决方案和这里的其他答案并不感到兴奋。 Sometimes when that happens, I rewrite in Ramda (disclaimer: I'm one of its authors) and then port the Ramda functions involved into vanilla JS.有时发生这种情况时,我会在 Ramda 中重写(免责声明:我是它的作者之一),然后将涉及的 Ramda 函数移植到 vanilla JS 中。 I'm not going to do the latter this time, but I will share how I might do this taking advantage of a library like Ramda.这次我不打算做后者,但我将分享如何利用像 Ramda 这样的库来做到这一点。 I'm guessing that there are similar features in lodash.我猜lodash中也有类似的功能。

 const groupByProp = (propName, childName) => pipe ( groupBy (prop (propName)), toPairs, map (evolve ([, map (dissoc (propName))])), map (zipObj ([propName, childName])) ) const transform = pipe ( groupByProp('KlasCode', 'Modules'), map (evolve ({Modules: groupByProp('ModuleID', 'Participation')})) ) let data1 = [{KlasCode: "AA", LESDatum: "06/02/2017", LESID: "1", ModuleID: "1061", ParticipationLetterCode: "Y"}, {KlasCode: "AA", LESDatum: "07/02/2017", LESID: "2", ModuleID: "1061", ParticipationLetterCode: "X"}, {KlasCode: "AA", LESDatum: "13/02/2017", LESID: "3", ModuleID: "1062", ParticipationLetterCode: "Z"}, {KlasCode: "BB", LESDatum: "16/02/2017", LESID: "4", ModuleID: "1063", ParticipationLetterCode: "X"}] console.log (transform (data1))
 .as-console-wrapper {min-height: 100%;important: top: 0}
 <script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script> <script> const {groupBy, prop, toPairs, map, evolve, dissoc, zipObj, pipe} = R </script>

I feel as though these functions are simpler and better show the steps of the transformation.我觉得这些功能好像更简单,更好地展示了转换的步骤。 But this is not enough of a reason to include a library.但这还不足以成为包含库的理由。 But once you have a few such situations, a library seems to make a great deal of sense.但是一旦你遇到了一些这样的情况,图书馆似乎就很有意义了。

I'm not trying to push Ramda here, just to point out that when you have the tools of a utility library at your disposal, you can often write simpler code.我不是要在这里推 Ramda,只是要指出,当您拥有实用程序库的工具时,您通常可以编写更简单的代码。

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

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