需求
处理以下树状数据,优雅的找到自己的祖先并用数组输出
let defaultDataa = [
{
name: '活动名称一',
},
{
name: '活动名称二',
children: [
{
name: '活动名称三',
children: [
{
name: '活动名称四',
children: [
{
name: '活动名称五',
},
],
},
],
},
],
},
];
find(defaultDataa, '活动名称四')[
// out
('活动名称二', '活动名称三', '活动名称四')
];
解决方法
这是我自己的解决方法,很普通的递归,真的很平凡。。
function find(array, text) {
for (let index = 0; index < array.length; index++) {
const element = array[index];
let { name, children } = element;
if (name == text) {
return [name];
} else {
if (children) {
let getChildrenArr = find(children, text);
if (getChildrenArr.length > 0) {
return [name, ...getChildrenArr];
}
}
}
}
return [];
}
console.log(find(testData, '活动名称四'));
德国巨佬 可爱的 kiochan 的方法,他还发现了我的一个 BUG,见后记,不看后悔
function find(arr, name) {
for (const o of arr) {
if (o && o.name) {
if (o.name === name) {
return [o.name];
} else if (o.children instanceof Array) {
const next = find(o.children, name);
if (next && next.length > 0) {
return [o.name, ...find(o.children, name)];
}
}
}
}
return null;
}
资深前端醒醒的方法,这代码太强了,看的我一脸茫然,让我意识到差距。注意一下代码中的注释
// 考虑的很全面,注意那个 key 和 children 可以自定义想找的数据类型。
const findDeep = (arr, val, { key = 'id', children = 'children' } = {}) => {
let list;
function find(v) {
if (v[key] === val) {
return this.push(v[key]) && (list = this);
}
if (v?.[children]?.length) {
return this.push(v[key]) && v[children].find(find, [...this]);
}
}
// 问了一下是不是可以用 map,他说这个方法找到了就不再进行递归了,速度快,我当时就觉得 NB
arr.find((v) => find.bind([])(v, val));
return list;
};
Max 大佬的方法,没有用到递归,这段代码值得一看 我得好好研究一下。。一下子没看懂。
来自大佬的解释: 基本逻辑就是 往 iter 里面塞对象,每个对象记录他的 path,虽然效率堪忧 基本上把整个数据集复制了一遍 不过下次使用的时候可以复用 可以把 iter 提出来做缓存,不过这个前提建立在数据不变 可以这么玩,不然的话 就是《gc 过着很难的日子》
function getPath(data, name) {
let iter = data.map((datum) => ({ ...datum, path: [] }));
for (let pos = 0; pos < iter.length; pos++) {
const item = iter[pos];
if (item.name === name) return [...item.path, name];
if (item.children)
iter = [
...iter,
...item.children.map((child) => ({
...child,
path: [...item.path, item.name],
})),
];
}
return false;
}
群友 成都 - 入门到放弃 - 嘻哈 的代码
function find(tree, field, val) {
let newArr = [];
tree.forEach((item) => {
let arr = [];
JSON.stringify(item, (a, b) => {
if (b[field]) arr.push(b[field]);
return b;
});
arr.reverse();
newArr = arr.slice(arr.findIndex((e) => e == val));
});
return newArr;
}
后记
上面的方法都是不断优化而来的,在写的过程中还发现了有意思的 BUG
我最初的代码是这样的,乍看上去没啥问题
function find(array, text) {
for (let index = 0; index < array.length; index++) {
const element = array[index];
let { name, children } = element;
if (name == text) {
return [name];
} else {
if (children) {
let getChildrenArr = find(children, text);
return [name, ...getChildrenArr];
}
}
}
return [];
}
严谨的德国巨佬 可爱的 kiochan 给出了这样的一个数据样本,注意活动名称四下面有一个空数组
const testData = [
{
name: '活动名称一',
},
{
name: '活动名称二',
children: [
{
name: '活动名称三',
children: [
{
name: '活动名称四',
children: [],
},
],
},
],
},
{
name: '活动名称二',
children: [
{
name: '活动名称三',
children: [
{
name: '活动名称四',
children: [
{
name: '活动名称五',
},
],
},
],
},
],
},
];
由于我没有做校验,递归到空数组那一块就停止了,输出了错误的结果。
然后我加上下面这段代码解决了问题
if (getChildrenArr.length > 0) {
return [name, ...getChildrenArr];
}