преобразовать массив из плоского 1-мерного в дерево, как в javascript / lodash - PullRequest
0 голосов
/ 04 мая 2020

У меня возникли проблемы с преобразованием следующего массива data1, чтобы он выглядел как data2: я пытался использовать loda sh, но это немного странно, _gropuby дает мне массив объектов. Должен ли я цикл внутри массива ... создание пользовательской функции для этого. или есть хитрость в loda sh, чтобы упростить это. 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"
      }]

    }]
  }

]

Ответы [ 3 ]

2 голосов
/ 04 мая 2020

Создана функция для того же, надеюсь, это поможет -:

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 голос
/ 04 мая 2020

Я бы использовал функцию groupBy в сочетании с небольшим переключением с Object.entries. Вам нужно будет использовать его дважды, чтобы справиться с вашими двумя уровнями группировки.

Вы можете использовать groupBy от loda sh (или тот, что от Рамды, или где угодно), или простой включенный здесь.

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}

Обновление - альтернатива Ramda

Меня не поразило ни вышеупомянутое решение, ни другие ответы здесь. Иногда, когда это происходит, я переписываю в Ramda (отказ от ответственности: я один из его авторов), а затем портирую функции Ramda, включенные в vanilla JS. Я не собираюсь делать последнее на этот раз, но я поделюсь, как я мог бы сделать это, используя в своих интересах библиотеку как Рамда. Я предполагаю, что в loda sh.

есть похожие функции.

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>

Мне кажется, что эти функции проще и лучше показывают этапы преобразования. Но этого недостаточно для включения библиотеки. Но если у вас есть несколько таких ситуаций, библиотека, кажется, имеет большой смысл.

Я не пытаюсь описать Рамду здесь, просто чтобы указать, что когда у вас есть инструменты утилита библиотека в вашем распоряжении, вы часто можете написать более простой код.

1 голос
/ 04 мая 2020

Вы можете использовать динамический подход c с массивом имен групп объявлений для ключей и извлекать ключи из реального объекта. В конце, после создания вложенных групп, добавьте последний объект в последнюю группу.

Этот подход работает для большего количества вложенных групп, если необходимо.

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