Это была очень интересная проблема для работы.
Мне нравится общая идея ответа от Нины Шольц, но мне действительно нужна была более общая c версия. Я придумал функцию, которая настроена примерно так:
[
{_children: 'subtasks', taskName: 'KlasCode'},
{_children: 'subtasks', taskName: 'Moduleomschrijving', ModuleID: 'ModuleID'},
{_children: 'subtasks', taskName: 'ParticipationLetterCode'},
{taskName: 'LESDatum'},
]
(см. Ниже код, чтобы узнать, как я мог бы изменить эту конфигурацию, если бы потратил больше времени на решение этой проблемы.)
Это говорит о том, что внешний уровень вывода получает свойство с именем taskName
из свойства KlasCode
, группируя по всем совпадающим значениям, и называет его массивом дочерних элементов subtasks
. Эти дети получают taskName
от Moduleomschrijving
и ModuleID
из ModuleID
, также называя своих детей subtasks
и т. Д. Последний узел преобразует имя LESDatum
в taskName
, но не имеет дочерних элементов, в которые можно было бы спуститься. Все остальные имена сохранены. Я сделал предположение, что Moduleomschrijving
и ModuleID
всегда синхронизируются c. Если это не так, то я могу упустить что-то важное.
Реализация зависит от двух вспомогательных функций:
groupBy
превращает массив в объект с ключами - результат вашей пользовательской функции и их массивы значений тех исходных элементов, которые генерируют ключ. omit
создает копию объекта с отсутствующими заданными ключами.
Такие функции доступны во многих служебных библиотеках. У нас также есть две основные функции.
nestGroup
: принимает один из этих объектов конфигурации и массив объектов, выполняет преобразование ключей, переименование свойств и детское гнездование. Это полезная функция сама по себе, она полезна, если у вас есть только один уровень вложенности.
nestGroups
: вызывает nestGroup
с использованием первого уровня предоставляется и рекурсивно вызывает nestGroups
с оставшимися уровнями конфигурации в массиве дочерних элементов. Он достигает дна, когда не осталось уровней, и просто возвращает массив без изменений.
Наконец, эта последняя функция каррирована, поэтому мы можем создать функцию многократного использования, которая встраивает нашу конфигурацию и принимает массив в качестве параметра. Это может быть полезно или не может быть полезно для OP, но я вижу, что это полезно в других местах. Мы воспользуемся этим, позвонив по номеру
const nestParticipations = nestGroups (config)
// ... later
const tree = nestParticipations (participations)
Но мы также можем просто сделать
const tree = nestGroups (config) (participations)
Вы можете увидеть это в действии здесь:
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}
Если бы я хотел потратить на это больше времени, думаю, я бы немного разбил это на части и, вероятно, использовал бы такую конфигурацию:
[
{ 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'} }
]
Это оставлено в качестве упражнения для читателя ...