[Vuejs]-Transform an array from a flat 1 dimensional to a tree like in javascript/lodash

2👍

Created a function to do the same, hope this helps -:

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))

1👍

You could take a dynamic approach with an array of keys ad group names and take the keys out of the actual object. At the end, after building nested groups, add the final object to the last group.

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

1👍

I would use a groupBy function in conjunction with a little fiddling with 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.

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

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. 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. I’m guessing that there are similar features in 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.

Leave a comment