переменная глубина
Вот адаптация к удивительному ответу Скотта, который позволяет вам преобразовать вложенную структуру в контролируемую пользователем глубину;convertUntil
-
- Если вход
o
не является объектом (базовый случай), преобразовать нечего, верните вход - В противном случае (индуктивно)вход является объектом. Если объект проходит пользовательский
test
, прекращает вложение и возвращает children: {}
- В противном случае (индуктивный) вход является объектом, но не не передать пользовательский
test
. Нанесите на карту входной объект и создайте уровень нашей выходной структуры. Повторите convertUntil
для каждого значения объекта.
Нумерованные комментарии выше соответствуют приведенному ниже коду -
const identity = x =>
x
const convertUntil = (test = identity, o = {}) =>
Object (o) !== o // 1
? o
: test (o) // 2
? {}
: Object
.entries (o) // 3
.map
( ([ k, v ]) =>
({ id: k, label: k, children: convertUntil (test, v) })
)
const myObj =
{ parent1:
{ child1: { lastChild1: { test: 'cool' } }
, child2: { lastChild2: { test: 'cool' } }
}
, parent2:
{ child2_1: { lastChild2_1: { test: 'cool' } }
, child2_2: { lastChild2_2: { test: 'cool' } }
}
}
console .log (convertUntil (x => x.test === "cool", myObj))
Хотя я предпочитаю эту более согласованную структуру данных, я могу понять, если вам не нравится пустой children: {}
, созданный выше. С небольшой модификацией мы можем удалить пустые children
свойства -
const identity = x =>
x
const convertUntil = (test = identity, o = {}) =>
Object (o) !== o
? o
: Object
.entries (o)
.map
( ([ k, v ]) =>
test (v) // <-- test here
? { id: k, label: k } // <-- no children
: { id: k, label: k, children: convertUntil (test, v) }
)
const myObj =
{ parent1:
{ child1: { lastChild1: { test: 'cool' } }
, child2: { lastChild2: { test: 'cool' } }
}
, parent2:
{ child2_1: { lastChild2_1: { test: 'cool' } }
, child2_2: { lastChild2_2: { test: 'cool' } }
}
}
console .log (convertUntil (x => x.test === "cool", myObj))
Но следите за -
console .log (convertUntil (x => x.test === "cool", { test: "cool" }))
// [ { id: "test", label: "test", children: "cool" } ]
фиксированная глубина
Другой вариант будетпреобразовать вложенную структуру в указанную depth
-
const identity = x =>
x
const convert = (o = {}, depth = 0) =>
Object (o) !== o
? o
: Object
.entries (o)
.map
( ([ k, v ]) =>
depth === 0 // <-- depth test
? { id: k, label: k } // <-- no children
: { id: k, label: k, children: convert (v, depth - 1) } // <-- depth minus one
)
const myObj =
{ parent1:
{ child1: { lastChild1: { test: 'cool' } }
, child2: { lastChild2: { test: 'cool' } }
}
, parent2:
{ child2_1: { lastChild2_1: { test: 'cool' } }
, child2_2: { lastChild2_2: { test: 'cool' } }
}
}
// show various depths
for (const d of [ 0, 1, 2 ])
console .log (`depth: ${d}`, convert (myObj, d))
комбинированная техника
Согласно комментарию Скотта, техники могут быть объединены в одно решение. Это позволяет пользователю продолжать преобразование на основе свойств объекта или указанного depth
уровня -
const identity = x =>
x
const convertUntil = (test = identity, o = {}, depth = 0) =>
Object (o) !== o
? o
: Object
.entries (o)
.map
( ([ k, v ]) =>
test (v, depth) // <-- include depth in test
? { id: k, label: k }
: { id: k, label: k, children: convertUntil (test, v, depth + 1) } // <-- depth plus one
)
const myObj =
{ parent1:
{ child1: { lastChild1: { test: 'cool' } }
, child2: { lastChild2: { test: 'cool' } }
}
, parent2:
{ child2_1: { lastChild2_1: { test: 'cool' } }
, child2_2: { lastChild2_2: { test: 'cool' } }
}
}
console .log (convertUntil ((_, depth) => depth === 2, myObj))