#javascript #recursion #ecmascript-6
#javascript #рекурсия #ecmascript-6
Вопрос:
Учитывая следующую структуру данных:
[
{
"name":"root",
"children":[
{
"name":"de",
"children":[
{
"name":"de",
"children":[
{
"name":"project-1",
"children":[
]
},
{
"name":"project-2",
"children":[
]
}
]
}
]
}
]
}
]
Ожидаемый:
[
{
"name":"project-1",
"children":[
]
},
{
"name":"project-2",
"children":[
]
}
]
Я хочу удалить уровень, если есть только один дочерний элемент. В этом примере я хочу иметь новый массив, который содержит только дочерние элементы «корневого» уровня без самого root.
Я бы сделал это с reduce
, но все еще не могу разобраться reduce
в сочетании с рекурсией. Есть идеи?
Комментарии:
1. извините, но не могли бы вы, пожалуйста, привести пример результирующего массива, который вы хотели бы иметь? Спасибо!
2. Пожалуйста, укажите ожидаемый массив. написанный вами код и текущий результат.
3. Отредактировал ожидаемый результат в описании
Ответ №1:
Вы можете просто использовать map и впоследствии сгладить массивы.
.map(o => o.children).flat()
РЕДАКТИРОВАТЬ: обновленный ответ после выяснения реального вопроса
Тем не менее, вы можете использовать map и flatten logic, но рекурсивным способом.
function removeSingleChildElms (o) {
if (!o.children) return
if (o.children.length === 1) {
return o.children.map(removeSingleChildElms).flat()
} else {
return o.children
}
}
ПРАВКА2:
Некоторое объяснение: Проблема заключается в преобразовании массива объектов в массив различных объектов. Я не выбираю reduce, потому что проблема не заботится о взаимосвязи / логике между родственными элементами. Речь идет всего лишь о преобразовании, следовательно, map будет работать достаточно хорошо.
Проблема требует «пропустить» объекты с 1 дочерним элементом. Это повторяющаяся часть, означающая: если вы видите объект, удовлетворяющий этому условию, вы переходите к более глубокому отображению. В любом другом допустимом условии дочерние элементы остаются неизменными (в противном случае)
Комментарии:
1. Это не учитывает данные, которые имеют дочерние элементы дочерних элементов
2. Он говорит: «Я хочу иметь новый массив, который содержит только дочерние элементы «корневого» уровня без самого root.». Это удаление корневого уровня. При вводе и выводе частей ‘and so an’ остается неизменным
3. Ну, это всего лишь пример. Алгоритм должен работать для всех входных данных. И так далее указывает на то, что существуют дополнительные уровни, где этот алгоритм должен быть применен. OP также заявляет, что он хочет использовать array.reduce и recursion, указывая, что он хочет обработать все слои
4. обновлен мой ответ
Ответ №2:
Преобразование дерева можно упростить, разбив задачу на две части:
- функция для преобразования одного узла
- функция для преобразования массива узлов
Чтобы преобразовать один узел, мы пишем transform1
- если дочерних элементов нет, мы нашли конечный узел, верните одноэлементный узел
- если есть только один дочерний элемент, удалите узел и верните преобразование его единственного дочернего элемента
- в противном случае узел имеет несколько дочерних элементов, вызовите нашу вторую функцию
transformAll
const transform1 = ({ children = [], ...node }) =>
children.length === 0 // leaf
? [ node ]
: children.length === 1 // singleton
? transform1 (...children)
: transformAll (children) // default
Чтобы преобразовать массив узлов, мы пишем transformAll
—
const transformAll = (arr = []) =>
arr .flatMap (transform1)
Как вы можете видеть, transformAll
вызывает transform1
, который также вызывает transformAll
. Этот метод называется взаимной рекурсией, и это отличный способ обрабатывать рекурсивные структуры данных, подобные предложенной в вашем вопросе.
Чтобы убедиться, что наша функция работает должным образом, я изменил дерево, чтобы оно содержало больше сценариев данных. Обратите внимание, наша программа работает для любых узлов со children
свойством. Все остальные свойства отображаются в результате —
const data =
[ { name: "a"
, children:
[ { name: "a.a"
, children:
[ { name: "a.a.a"
, children: []
}
, { name: "a.a.b"
, foo: 123
, children: []
}
]
}
]
}
, { name: "b"
, children:
[ { name: "b.a"
, children:
[ { name: "b.a.a"
, children: []
}
, { name: "b.a.b"
, children: []
}
]
}
, { name: "b.b"
, children: []
}
]
}
, { name: "c"
, children: []
}
]
Мы можем выполнить transformAll
обработку ваших данных для преобразования всех узлов —
transformAll (data)
// [ { name: 'a.a.a' }
// , { name: 'a.a.b', foo: 123 }
// , { name: 'b.a.a' }
// , { name: 'b.a.b' }
// , { name: 'b.b' }
// , { name: 'c' }
// ]
Или для преобразования одного узла мы вызываем transform1
—
transform1 (data[0])
// [ { name: 'a.a.a' }
// , { name: 'a.a.b', foo: 123 }
// ]
transform1 (data[2])
// [ { name: 'c' } ]
Разверните приведенный ниже фрагмент, чтобы проверить результаты в вашем собственном браузере —
const data =
[ { name: "a"
, children:
[ { name: "a.a"
, children:
[ { name: "a.a.a"
, children: []
}
, { name: "a.a.b"
, foo: 123
, children: []
}
]
}
]
}
, { name: "b"
, children:
[ { name: "b.a"
, children:
[ { name: "b.a.a"
, children: []
}
, { name: "b.a.b"
, children: []
}
]
}
, { name: "b.b"
, children: []
}
]
}
, { name: "c"
, children: []
}
]
const transform1 = ({ children = [], ...node }) =>
children.length === 0 // leaf
? [ node ]
: children.length === 1 // singleton
? transform1 (...children)
: transformAll (children) // default
const transformAll = (arr = []) =>
arr .flatMap (transform1)
console .log (transformAll (data))
// [ { name: 'a.a.a' }
// , { name: 'a.a.b', foo: 123 }
// , { name: 'b.a.a' }
// , { name: 'b.a.b' }
// , { name: 'b.b' }
// , { name: 'c' }
// ]