Для меня имеет смысл отделить рекурсивный обход и фильтрацию от фактических деталей удаления определенного идентификатора. Поэтому я бы написал более общую функцию c filterDeep
, которая сохраняет только те объекты, для которых предикат истинен, рекурсивно переходя в children
узлы.
Затем мы можем предоставить ему предикат, который проверяет, элемент соответствует указанному c id. Или, скорее, поскольку мы удаляем те, которые совпадают, наш предикат на самом деле проверяет, соответствует ли наш узел идентификатору.
Это реализация этой идеи:
const filterDeep = (pred) => (xs) =>
xs .flatMap (x => pred (x)
? [{... x, children: filterDeep (pred) (x .children || [])}]
: []
)
const removeId = (id) =>
filterDeep (x => x.id !== id)
const myArray = [{id: 1, children: [{id: 3, children: []}]}, {id: 2, children: []}]
console .log (removeId (1) (myArray))
console .log (removeId (2) (myArray))
console .log (removeId (3) (myArray))
console .log (removeId (42) (myArray))
.as-console-wrapper {min-height: 100% !important; top: 0}
Это будет включать узел children
, даже если у оригинала его не было. Если бы мы хотели включить его только в том случае, если он был изначально, мы могли бы изменить его на что-то вроде этого:
const filterDeep = (pred) => (xs) =>
xs .flatMap (x => pred (x)
? [{
... x,
... (x.children ? {children: filterDeep (pred) (x .children || [])} : {})
}]
: []
)
Или, что немного сложнее, мы могли бы включить только узел children
когда он доступен в родительском элементе и результаты непустые. Это оставлено в качестве упражнения для читателя. : -)