У меня есть массив объектов с иерархической структурой, что-то вроде этого:
[
{name: 'ParentOne', children: [
{name: 'ParentOneChildOne'},
{name: 'ParentOneChildTwo', children: [
{name: 'ParentOneChildTwoGrandChildOne'},
]},
]},
{name: 'ParentTwo', children: [
{name: 'ParentTwoChildOne', children: [
{name: 'ParentTwoChildOneGrandChildOne'},
{name: 'ParentTwoChildOneGrandChildTwo'}
]},
{name: 'ParentTwoChildTwo'}
]}
];
Я хочу сгладить его:
[
{name: 'ParentOne'},
{name: 'ParentOneChildOne'},
{name: 'ParentOneChildTwo'},
{name: 'ParentOneChildTwoGrandChildOne'},
{name: 'ParentTwo'},
{name: 'ParentTwoChildOne'},
{name: 'ParentTwoChildOneGrandChildOne'},
{name: 'ParentTwoChildOneGrandChildTwo'},
{name: 'ParentTwoChildTwo'}
]
Я пробовал _.flatten()
и _.flatMap()
, но он не создает то, что мне нужно. Каков наилучший способ его достижения, предпочтительно используя lodash.js или underscore.js.
Не нужно подчеркивать /lodash.
const arr = [
{name: 'ParentOne', children: [
{name: 'ParentOneChildOne'},
{name: 'ParentOneChildTwo', children: [
{name: 'ParentOneChildTwoGrandChildOne'},
]},
]},
{name: 'ParentTwo', children: [
{name: 'ParentTwoChildOne', children: [
{name: 'ParentTwoChildOneGrandChildOne'},
{name: 'ParentTwoChildOneGrandChildTwo'}
]},
{name: 'ParentTwoChildTwo'}
]}
];
function flatten(arr) {
return arr? arr.reduce((result, item) => [
...result,
{ name: item.name },
...flatten(item.children)
], []) : [];
}
console.log(flatten(arr));
Рекурсивные функции - это путь для любой глубины итерации.
С некоторыми ES2015 и LoDash/Underscore
var arr = [{
name: 'ParentOne',
children: [{
name: 'ParentOneChildOne'
}, {
name: 'ParentOneChildTwo',
children: [{
name: 'ParentOneChildTwoGrandChildOne'
}, ]
}, ]
}, {
name: 'ParentTwo',
children: [{
name: 'ParentTwoChildOne',
children: [{
name: 'ParentTwoChildOneGrandChildOne'
}, {
name: 'ParentTwoChildOneGrandChildTwo'
}]
}, {
name: 'ParentTwoChildTwo'
}]
}];
var res = _.reduce(arr, (a, b) => {
(rec = item => {
_.each(item, (v, k) => (_.isObject(v) ? rec(v) : a.push(_.zipObject([k], [v]))))
})(b);
return a;
}, []);
console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
Я бы использовал .reduce
и .reduce
чтобы сделать это. Здесь моя реализация с использованием Array.reduce, но вы можете сделать то же самое с функцией сокращения подчеркивания.
const arr = [
{name: 'ParentOne', children: [
{name: 'ParentOneChildOne'},
{name: 'ParentOneChildTwo', children: [
{name: 'ParentOneChildTwoGrandChildOne'},
]},
]},
{name: 'ParentTwo', children: [
{name: 'ParentTwoChildOne', children: [
{name: 'ParentTwoChildOneGrandChildOne'},
{name: 'ParentTwoChildOneGrandChildTwo'}
]},
{name: 'ParentTwoChildTwo'}
]}
];
function flatten(arr) {
return arr.reduce((result, current) => {
if (current.children) {
const children = flatten(current.children);
delete current.children;
result.push(current);
result.push(...children);
} else {
result.push(current);
}
return result;
}, [])
}
console.log(flatten(arr));
Вы можете использовать некоторое уничтожение и использовать рекурсивную функцию для сбора всех необходимых предметов.
var array = [{ name: 'ParentOne', children: [{ name: 'ParentOneChildOne' }, { name: 'ParentOneChildTwo', children: [{ name: 'ParentOneChildTwoGrandChildOne' },] },] }, { name: 'ParentTwo', children: [{ name: 'ParentTwoChildOne', children: [{ name: 'ParentTwoChildOneGrandChildOne' }, { name: 'ParentTwoChildOneGrandChildTwo' }] }, { name: 'ParentTwoChildTwo' }] }],
flat = (r, { name, children = [] }) => [...r, { name }, ...children.reduce(flat, []) ],
result = array.reduce(flat, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
В EDGE вам нужно другое использование значений defualt
var array = [{ name: 'ParentOne', children: [{ name: 'ParentOneChildOne' }, { name: 'ParentOneChildTwo', children: [{ name: 'ParentOneChildTwoGrandChildOne' },] },] }, { name: 'ParentTwo', children: [{ name: 'ParentTwoChildOne', children: [{ name: 'ParentTwoChildOneGrandChildOne' }, { name: 'ParentTwoChildOneGrandChildTwo' }] }, { name: 'ParentTwoChildTwo' }] }],
flat = (r, { name, children }) => [...r, { name }, ...(children || []).reduce(flat, []) ],
result = array.reduce(flat, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Вы можете попытаться адаптировать функцию flatten
данную в этом ответе, и слегка перевернуть логику в свою структуру объекта.
//Your object
var data = [{
name: 'ParentOne',
children: [{
name: 'ParentOneChildOne'
},
{
name: 'ParentOneChildTwo',
children: [{
name: 'ParentOneChildTwoGrandChildOne'
}, ]
},
]
},
{
name: 'ParentTwo',
children: [{
name: 'ParentTwoChildOne',
children: [{
name: 'ParentTwoChildOneGrandChildOne'
},
{
name: 'ParentTwoChildOneGrandChildTwo'
}
]
},
{
name: 'ParentTwoChildTwo'
}
]
}
];
//georg flatten function
flatten = function(x, result, prefix) {
if (_.isObject(x)) {
_.each(x, function(v, k) {
flatten(v, result, prefix ? prefix + '_' + k : k)
})
} else {
result[prefix] = x
}
return result
}
//using the function on your data
result = flatten(data, {});
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
Помогает ли это вообще?