Daily-Interview-Question icon indicating copy to clipboard operation
Daily-Interview-Question copied to clipboard

第 92 题:已知数据格式,实现一个函数 fn 找出链条中所有的父级 id

Open yygmind opened this issue 5 years ago • 127 comments

const value = '112'
const fn = (value) => {
...
}
fn(value) // 输出 [1, 11, 112]

yygmind avatar Jun 18 '19 15:06 yygmind

const data = [{
    id: '1',
    name: 'test1',
    children: [
        {
            id: '11',
            name: 'test11',
            children: [
                {
                    id: '111',
                    name: 'test111'
                },
                {
                    id: '112',
                    name: 'test112'
                }
            ]

        },
        {
            id: '12',
            name: 'test12',
            children: [
                {
                    id: '121',
                    name: 'test121'
                },
                {
                    id: '122',
                    name: 'test122'
                }
            ]
        }
    ]
}];
const find = (value) => {
    let result = [];
    let findArr = data;
    let skey = '';
    for (let i = 0, l = value.length; i < l; i++) {
        skey += value[i]
        let item = findArr.find((item) => {
            return item.id == skey
        });

        if (!item) {
            return [];
        }

        result.push(item.id);
        if (item.children) {
            findArr = item.children;
        } else {
            if (i < l - 1) return []
            return result;
        }

    }

}
//调用看结果
function testFun() {
    console.log('1,11,111:', find('111'))
    console.log('1,11,112:', find('112'))
    console.log('1,12,121:', find('121'))
    console.log('1,12,122:', find('122'))
    console.log('[]:', find('113'))
    console.log('[]:', find('1114'))
}

Zephylaci avatar Jun 19 '19 01:06 Zephylaci

dfs

const fn = (data, value) => {
  let res = []
  const dfs = (arr, temp = []) => {
    for (const node of arr) {
      if (node.children) {
        dfs(node.children, temp.concat(node.id))
      } else {
        if (node.id === value) {
          res = temp
        }
        return
      }
    }
  }
  dfs(data)
  return res
}

ZodiacSyndicate avatar Jun 19 '19 01:06 ZodiacSyndicate

let list = [{
    id: '1',
    children: [{
        id: '11',
        children: [{
            id: '111'
        }, {
            id: '112'
        }]
    }]
}];

function fn(value) {
    // 回溯的标记
    let _p = Symbol('parent');
    // 找到子节点
    let result;
    function _fn(arr, p) {
        for (let i = 0; i < arr.length; i++) {
            arr[i][_p] = p;
            if (arr[i].id === value) {
                result = arr[i];
                return;
            }
            !result && arr[i].children && _fn(arr[i].children, arr[i])
        }
        if (result) return;
    }
    _fn(list, null);
    let tmp = [];
    if (!result) return null;
    while (result) {
        tmp.unshift(result.id);
        result = result[_p];
    }
    return tmp;
}

思路是找到子节点,再回溯找父节点 复杂度是O(n),循环n次子节点,但是需要额外空间记录父节点引用

kungithub avatar Jun 19 '19 02:06 kungithub

const findItem = (value, list, graph) => {
    return list.some(item => {
        if (item.id === value) {
            graph.push(item.id)
            return true
        }
        if (item.children) {
            graph.push(item.id)
            return findItem(value, item.children, graph)
        }
    })
}

const fn = value => {
    let graph = []
    list.some(item => {
        graph.push(item.id)
        if (item.id === value) return true
        if (item.children) {
            let res = findItem(value, item.children, graph)
            if (!res) graph = []
            return res
        }
    })
    return graph
}

实现的思路是记录每次 dfs 遍历的路径,当找到元素时,返回记录的所有路径,找不到时清空路径遍历下个元素

希望有更好的解法

var list = [{
	id: '1',
	children: [{
		id: '11',
		children: [{
			id: '111'
		}, {
			id: '112'
		}]
	}, {
		id: '12',
		children: [{
			id: '121'
		}, {
			id: '122'
		}]
	}]
}]

const value = '122';

这个情景不太对吧

sgzhm4444 avatar Jun 19 '19 02:06 sgzhm4444

const findItem = (value, list, graph) => {
    return list.some(item => {
        if (item.id === value) {
            graph.push(item.id)
            return true
        }
        if (item.children) {
            graph.push(item.id)
            return findItem(value, item.children, graph)
        }
    })
}

const fn = value => {
    let graph = []
    list.some(item => {
        graph.push(item.id)
        if (item.id === value) return true
        if (item.children) {
            let res = findItem(value, item.children, graph)
            if (!res) graph = []
            return res
        }
    })
    return graph
}

实现的思路是记录每次 dfs 遍历的路径,当找到元素时,返回记录的所有路径,找不到时清空路径遍历下个元素 希望有更好的解法

var list = [{
	id: '1',
	children: [{
		id: '11',
		children: [{
			id: '111'
		}, {
			id: '112'
		}]
	}, {
		id: '12',
		children: [{
			id: '121'
		}, {
			id: '122'
		}]
	}]
}]

const value = '122';

这个情景不太对吧

嗯我再研究一下~

yeyan1996 avatar Jun 19 '19 02:06 yeyan1996

@ZodiacSyndicate 这个写法想查112的时候不就查不出来了..

Zephylaci avatar Jun 19 '19 03:06 Zephylaci

  • bfs利用队列实现,循环中做的是push => shift => push => shift
  • dfs利用栈实现,循环中做的是push => pop => push => pop

刚刚好,中间仅仅差了一个数组方法:

function bfs(target, id) {
  const quene = [...target]
  do {
    const current = quene.shift()
    if (current.children) {
      quene.push(...current.children.map(x => ({ ...x, path: (current.path || current.id) + '-' + x.id })))
    }
    if (current.id === id) {
      return current
    }
  } while(quene.length)
  return undefined
}

function dfs(target, id) {
  const stask = [...target]
  do {
    const current = stask.pop()
    if (current.children) {
      stask.push(...current.children.map(x => ({ ...x, path: (current.path || current.id) + '-' + x.id })))
    }
    if (current.id === id) {
      return current
    }
  } while(stask.length)
  return undefined
}

// 公共的搜索方法,默认bfs
function commonSearch(target, id, mode) {
  const staskOrQuene = [...target]
  do {
    const current = staskOrQuene[mode === 'dfs' ? 'pop' : 'shift']()
    if (current.children) {
      staskOrQuene.push(...current.children.map(x => ({ ...x, path: (current.path || current.id) + '-' + x.id })))
    }
    if (current.id === id) {
      return current
    }
  } while(staskOrQuene.length)
  return undefined
}

lhyt avatar Jun 19 '19 05:06 lhyt

        const fn = (value) => {
            let graph = []
            const mapData = new Map();
            function ParentMap(data, parentId) {
                parentId = parentId || 0;
                data.forEach(item => {
                    mapData[item.id] = { ...item, parentId }
                    if (item.children) {
                        ParentMap(item.children, item.id);
                    }
                })
            }
            ParentMap(data)
            function getId(data, value) {
                graph.unshift(data[value].id)
                if (data[value].parentId !== 0) {
                    getId(data, data[value].parentId)
                }
            }
            getId(mapData, value)
            return graph;
        }

Rashomon511 avatar Jun 19 '19 05:06 Rashomon511

/*
* 已知数据格式,实现一个函数 fn 找出链条中所有的父级 id 
* 实现: 通过es6的class实现,思路:递归调用,下传当前的父辈的id
*/
class FindFather{
    constructor() {
        this.data = this.init(),
        this.target = null;
    }
    dfs(value,data,idArr) {
        var that = this;
        data.forEach((item, index) => {
            item.idArr = idArr.concat(item.id)
            if(item.id === value) {
                this.target = item.idArr;
            }
            if(item.children){
                return this.dfs(value, item.children, item.idArr)
            }
        })
    }
    result() {
        return this.target;
    }
    init() {
        return [{
            id: '1',
            name: 'test1',
            children: [
                {
                    id: '11',
                    name: 'test11',
                    children: [
                        {
                            id: '111',
                            name: 'test111'
                        },
                        {
                            id: '112',
                            name: 'test112'
                        }
                    ]

                },
                {
                    id: '12',
                    name: 'test12',
                    children: [
                        {
                            id: '121',
                            name: 'test121'
                        }
                    ]
                }
            ]
        }];
    }
    
}
var find = new FindFather();
find.dfs('112',find.data, [])
console.log(find.result())  //["1","12","121"]

GuoYuFu123 avatar Jun 19 '19 06:06 GuoYuFu123

const data = [{
    id: '1',
    name: 'test1',
    children: [
        {
            id: '11',
            name: 'test11',
            children: [
                {
                    id: '111',
                    name: 'test111'
                },
                {
                    id: '112',
                    name: 'test112'
                }
            ]
        },
        {
            id: '12',
            name: 'test12',
            children: [
                {
                    id: '121',
                    name: 'test121',
                    children: [
                        {
                            id: '1221',
                            name: 'test121',
                            children:[
                                {
                                    id:'12345'
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    ]
},
{
    id:'1234',
    children:[
        {
            id:'567'
        }
    ]
}
]
const value = '112'
const fn = (value) => {
    let err = 'return start'
    let interim = JSON.parse(JSON.stringify(data))
    let result = []
    try {
        while (interim.length > 0) {
            let point = interim.pop() 
            let child = point.children
            let queue = child
            let cresult = []
            result.push(point.id)
            while (queue && queue.length > 0) {
                let cpoint = queue.pop()
                cresult.push(cpoint.id)
                if (!cpoint.children || cpoint.id == value) {
                    if (cresult.indexOf(value) > -1) {
                        queue.length = 0
                    } else {
                        cresult = []
                    }
                    continue
                }
                queue.push(...cpoint.children)
            }
            if (result.concat(cresult).indexOf(value) > -1) {
                result = result.concat(cresult)
                throw new Error(err)
            } else {
                result = []
            }
        }
    } catch (e) {
        if (e.message === err) {
            console.log(result.map(v => parseInt(v)))
            return result.map(v => parseInt(v))
        } else {
            throw e
        }
    }

}
fn(value) // 输出 [1, 11, 112]
fn('1234') // 输出 [1234]
fn('12345') // 输出 [1, 12, 121, 1221, 12345]

写法是深度优先, 增加了数据结构的深度与广度,能可以正确输出

18692959234 avatar Jun 19 '19 06:06 18692959234

function dfsFn(list, value) {
  let res = []

  function dfs(arr, ids=[]) {
    for (const item of arr) {
      if (item.id === value) {
        res = [...ids, ...[item.id]]
        return
      } else {
        if (item.children) {
          dfs(item.children, ids.concat([item.id]))
        }
      }
    }
  }

  dfs(list)

  return res
}

lvwxx avatar Jun 19 '19 07:06 lvwxx

const data = [{
    id: '1',
    name: 'test1',
    children: [
        {
            id: '11',
            name: 'test11',
            children: [
                {
                    id: '111',
                    name: 'test111'
                },
                {
                    id: '112',
                    name: 'test112'
                }
            ]
        },
        {
            id: '12',
            name: 'test12',
            children: [
                {
                    id: '121',
                    name: 'test121'
                },
                {
                    id: '122',
                    name: 'test122'
                }
            ]
        }
    ]
}];

let res = [];

const findId = (list, value) => {
  let len = list.length;

  for (let i in list) {
    const item = list[i];

    if (item.id == value) {
      return res.push(item.id), [item.id];
    }

    if (item.children) {
      if (findId(item.children, value).length) {
        res.unshift(item.id);
        return res;
      }
    }

    if (i == len - 1) {
      return res;
    }
  }
};

// res =  []
findId(data, '123'); 

// res = [ '1' ]
findId(data, '1');   

// res = [ '1', '12' ]      
findId(data, '12');    

// res = [ '1', '12', '122' ]  
findId(data, '122');    

B2D1 avatar Jun 19 '19 17:06 B2D1

function getIdChain(data, id, idkey = "id", childrenKey = "children") {
  if (check(data, id)) {
    return [];
  }

  loop.chain = [];
  loop(data, id);
  return loop.chain;

  function check(data, id) {
    return !Array.isArray(data) || !data.length || (!id && id !== 0);
  }

  function loop(arr, v) {
    if (check(arr, v)) {
      return false;
    }
    return arr.some(i => {
      return i[idkey] === v || (i[childrenKey] && loop(i[childrenKey], v))
        ? (loop.chain.unshift(i[idkey]), true)
        : false;
    });
  }
}


nailfar avatar Jun 20 '19 03:06 nailfar

评论好多直接复制黏贴都是错的,发之前先测试一下啊,另外如果按照示例中省市区id的规则,可以找到目标 id 然后直接推倒出所有父 id 的吧....

let res = []
let value = '112'
for(let i = 0;i<value.length;i++){
    res.push(value.slice(0,i+1))
}
console.log(res)

yeyan1996 avatar Jun 20 '19 07:06 yeyan1996

const value = '112' const fn = (value) => { let vals = value.split(''); //1 11 112 for (let i = 0; i < vals.length; i++) { let v = vals.slice(0,i+1).join('') console.log(v) } } fn(value)

LGwen avatar Jun 20 '19 09:06 LGwen

const fn = (str) => [...str].reduce((prev, next) => [...prev, prev.slice(-1) + next], [])

simon-woo avatar Jun 20 '19 10:06 simon-woo

const bfs = data => {
  const queue = [...data]
  let res = []
  while(queue.length) {
    let node = queue.shift()
    if (node.children) {
      for (let child of node.children) {
        queue.push(child)
      }
      res.push(node.id)
    }
  }
  return res
}

xxyGoTop avatar Jun 20 '19 10:06 xxyGoTop

评论好多直接复制黏贴都是错的,发之前先测试一下啊,另外如果按照示例中省市区id的规则,可以找到目标 id 然后直接推倒出所有父 id 的吧....

let res = []
let value = '112'
for(let i = 0;i<value.length;i++){
    res.push(value.slice(0,i+1))
}
console.log(res)

仔细看了下题目意图应该是通过这个id值 解析出所有父级链路,但是根据数据截图,这样推演下去34个省 可能会出现 3411 34512 这就没法玩了 省应该至少占两位 01 - 34 ; 为了出题而出的题 ,没有实用价值

nailfar avatar Jun 21 '19 02:06 nailfar

const tree = {
  id: '1',
  name: 'test1',
  children: [
      {
          id: '11',
          name: 'test11',
          children: [
              {
                  id: '111',
                  name: 'test111'
              },
              {
                  id: '112',
                  name: 'test112'
              }
          ]
      },
      {
          id: '12',
          name: 'test12',
          children: [
              {
                  id: '121',
                  name: 'test121'
              },
              {
                  id: '122',
                  name: 'test122'
              }
          ]
      }
  ]
};

interface Area {
  id: string,
  name: string,
  children?: Array<Area>
};

function findAllParentId(tree: Area, id: string) {
  const stack = [tree];
  while(stack.length > 0) {
    const top = stack.slice().pop();
    if (top.id === id) break;

    if (top.children && top.children.length>0) {
      const cTop = top.children.pop();
      stack.push(cTop);
    } else {
      stack.pop();
    }
  }
  return stack.map(n => n.id);
}

const deepCopy = obj => JSON.parse(JSON.stringify(obj));
const idList = findAllParentId(deepCopy(tree), '122');
console.log(`${idList}`);

经典数据结构的深度遍历结构

benzhemin avatar Jun 21 '19 14:06 benzhemin

dfs

const fn = (data, value) => {
  let res = []
  const dfs = (arr, temp = []) => {
    for (const node of arr) {
      if (node.children) {
        dfs(node.children, temp.concat(node.id))
      } else {
        if (node.id === value) {
          res = temp
        }
        return
      }
    }
  }
  dfs(data)
  return res
}

为什么运行结果不对

wangyuanyuan0521 avatar Jun 23 '19 08:06 wangyuanyuan0521

@wangyuanyuan0521
@ZodiacSyndicate

function fn(data, value) {
  let res = []
  const dfs = (arr, temp = []) => {
    for (const node of arr) {
      if (node.id === value) {
        res = temp
        return
      } else {
        node.children && dfs(node.children, temp.concat(node.id))
      }
    }
  }
  dfs(data)
  return res
}

Meqn avatar Jun 24 '19 06:06 Meqn

const cityData = [{
    id: '1',
    name: '广东省',
    children: [
      {
        id: '11',
        name: '深圳市',
        children: [
          {
            id: '111',
            name: '南山区'
          },
          {
            id: '112',
            name: '福田区',
            children: [{
              id: '1121',
              name: 'A街道'
            }]
          }
        ]
      },
      {
        id: '12',
        name: '东莞市',
        children: [
          {
            id: '121',
            name: 'A区'
          },
          {
            id: '122',
            name: 'B区',
          }
        ]
      }
    ]
  }];

  const tarId = '1121'
  const findId = (data, tarId, parentId = []) =>
    data.reduce((acc, item) =>
      acc.concat(item.id == tarId
        ? [...parentId, item.id]
        : item.children
          ? findId(item.children, tarId, [...parentId, item.id])
          : [])
      , [])

  let res = findId(cityData, tarId) // 输出 [1, 11, 112, 1121]
  console.log(res)

k-0311 avatar Jun 25 '19 02:06 k-0311

源码

const fn = (value, radix = 1) =>
  Array.from(new Array(value.length / radix)).reduce(
    (al, _, idx) => [...al, value.slice(0, radix * (idx + 1))],
    []
  );

测试

fn('112') // ["1", "11", "112"]
fn('123456789', 3) // ["123", "123456", "123456789"]

解释

用途:用来把地址串转换为地址数组,常用于地址选择器,这里支持任何方式分割(常用于6 位地址每两位分割一次) 原理很简单,字符串是有规律的(每个更详细串包含父级串),就是简单的字符串分割(循环每次取前radix*(idx+1)范围的子串)

lovelope avatar Jul 03 '19 15:07 lovelope

评论好多直接复制黏贴都是错的,发之前先测试一下啊,另外如果按照示例中省市区id的规则,可以找到目标 id 然后直接推倒出所有父 id 的吧....

let res = []
let value = '112'
for(let i = 0;i<value.length;i++){
    res.push(value.slice(0,i+1))
}
console.log(res)

其实我也想问这个问题:

  • 如果id是有规律的,最容易处理,通过id解析出结果, 其他情况的重点是优先找到目标节点
  • 如果id的位数和层级有关系, 处理方法就要根据id,判断不同的层级, 做不同的处理(少很多递归)
  • 如果id和层级没有关系,就需要权衡是深度优先还是广度优先做处理

Kntt avatar Jul 09 '19 08:07 Kntt

const arr = [
    {
        id: 1,
        name: '广东',
        children: [
            {
                id: 11,
                name: '深圳',
                children: [
                    {
                        id: 111,
                        name: '南山区'
                    },
                    {
                        id: 112,
                        name: '福田区'
                    }
                ]
            }
        ]
    }
]

const id = 112

const fn = (treeData, idsList = [], ids = []) => {
    treeData.forEach(item => {
        const { id, children } = item
        const tempIds = [].concat(ids)
        tempIds.push(id)

        idsList.push(tempIds);

        if (children && !!children.length) {
            fn(children, idsList, tempIds);
        }
    });

    return idsList;
};

const list = fn(arr)


const result = list.filter(item => {
    const lastValue = item[item.length - 1]

    return Number(lastValue) === Number(id)
})

思路: 1、将数组转换为多个一维数组,结果如下所示: image 2、循环第一步所得的结果,判断最后一位是不是和要查询的id相同,如果是那么就返回结果

mcfly001 avatar Jul 09 '19 12:07 mcfly001

为了可读性,牺牲了部分复杂度。

代码:

function fn(id, list) {
  const match = list.find(item => item.id === id);
  if (match) return [id];
  const sub = list.find(item => id.startsWith(item.id));
  return [sub.id].concat(fn(id, sub.children));
}

azl397985856 avatar Jul 11 '19 03:07 azl397985856

const data = [{
    id: '1',
    name: 'test1',
    children: [
        {
            id: '11',
            name: 'test11',
            children: [
                {
                    id: '111',
                    name: 'test111'
                },
                {
                    id: '112',
                    name: 'test112'
                }
            ]

        },
        {
            id: '12',
            name: 'test12',
            children: [
                {
                    id: '121',
                    name: 'test121'
                },
                {
                    id: '122',
					name: 'test122',
					children:[
						{
							id: '1221',
							name: 'test121'
						},
					]
                }
            ]
        }
    ]
}];

function findValue(data,valie){
	var key = [];
	function find (data,value){
		for(let i=0; i<data.length;i++){
			if(data[i].id === value){
				key.push(data[i].id)
				break
			}
			if(data[i].children && data[i].children.length > 0){
				if(find(data[i].children,value).length > 0){
					key.push(data[i].id)
					break;
				}
			}
		}
		return key
	}
	find(data,valie)
	return key
}
console.log(findValue(data,'1221'))

yanzhandong avatar Jul 15 '19 04:07 yanzhandong

刚好有类似需求,试完答案竟然基本都是错的,自己试试。

const data = [{
  id: 1,
  children: [{
    id: 2,
    children: [{
      id: 3
    }, {
      id: 4
    }]
  }]
}];

let find = (function () {
  let map = null;
  let findMap = (data, ids, map = {}) => {
    data.forEach(item => {
      map[item.id] = map[item.id] || [];
      if (ids) {
        map[item.id] = ids.concat(item.id);
      } else {
        map[item.id].push(item.id);
      }
      if (item.children) {
        return findMap(item.children, map[item.id], map);
      }
    });
    return map;
  }
  return function (value) {
    if (!map) {
      map = findMap(data);
    }
    return map[value];
  }
})();

console.log(find(1)) // [1]
console.log(find(2)) // [1, 2]
console.log(find(3)) // [1, 2, 3]
console.log(find(4)) // [1, 2, 4]

jununx avatar Jul 16 '19 05:07 jununx

'use strict';

/**
 * @description: 典型的树状结构遍历算法,从某顶点到某顶点的深度优先算法。
 * 遍历顶点V的相邻节点,如果子节点有孙节点则递归遍历孙节点
 * 用一个栈来存储路径。
 * @author: zpp
 * @date: 2019-07-16
 */

const province = [
  {
    id: "1",
    name: "广东省",
    children: [
      {
        id: "11",
        name: "深圳市",
        children: [
          {id: "111", name: "罗湖区"},
          {id: "112", name: "南山区"},
          {id: "113", name: "福田区", children: [{id:'1131',name:'下沙'}]}
        ]
      }, {
        id: "12",
        name: "惠州"
      },
      {
        id: "13",
        name: "广州",
        children: [{id:'131',name:'花都'}]
      }
    ]
  }
]

let fnc = (value) => {

  let res = [] // 用来存放最终路径
  let dfs = function(arr, path=[]){

    for(let item of arr ){ // 遍历顶点的所有邻居节点

      if(item.id === value){
        path.push(item.id) // 将最后一个路径存进去,返回找到的路径,并退出循环
        res = path
        return
      }else{
        console.log('push_stack_id:', item.id)
        path.push(item.id)
        if(item.children){
          dfs(item.children, path)
        }else{
          let _popNoChild = path.pop()
          console.log('pop_no_child: ',_popNoChild)
        }
      }
    }

    if(!res.length){
      let _popCurrentNode = path.pop()
      console.log('pop_current_node:', _popCurrentNode)
    }

  }


  dfs(province)
  console.log('res',res)
  return res
}

fnc('131')

narycc avatar Jul 18 '19 12:07 narycc

深度优先遍历(DFS)


var resABC = [
    {
        "id": 1,
        "name": "部门A",
        "parentId": 0,
        "children": [
            {
                "id": 3,
                "name": "部门C",
                "parentId": 1,
                "children": [
                    {
                        "id": 6,
                        "name": "部门F",
                        "parentId": 3
                    }
                ]
            },
            {
                "id": 4,
                "name": "部门D",
                "parentId": 1,
                "children": [
                    {
                        "id": 9,
                        "name": "部门H",
                        "parentId": 4
                    },
                    {
                        "id": 8,
                        "name": "部门HH",
                        "parentId": 4
                    }
                ]
            }
        ]
    },
    {
        "id": 2,
        "name": "部门B",
        "parentId": 0,
        "children": [
            {
                "id": 5,
                "name": "部门E",
                "parentId": 2
            },
            {
                "id": 7,
                "name": "部门G",
                "parentId": 2
            }
        ]
    }
];

const fn = function (array, value) {
    var flag = 0;
    var result = [];
    const findId = function (array, [...resParentIds]) {
        for (let index = 0; index < array.length; index++) {
            if (flag === 1) break;
            const element = array[index];
            if (index > 0) {
                resParentIds.pop();
            }
            resParentIds.push(element.id);
            if (element.id === value) {
                flag = 1;
                result = resParentIds;
                break;
            } else {
                if (element.children) {
                    findId(element.children, resParentIds);
                }
            }
        }
    }
    findId(array, []);
    return result;
}
console.log(fn(resABC, 8));   // [1, 4, 8]
console.log(fn(resABC, 7));   // [2, 7]
console.log(fn(resABC, 5));   // [2, 5]

richard1015 avatar Jul 22 '19 09:07 richard1015

let list = [
        {
            id: '1',
            name: '广东省',
            children: [
                {
                    id: '11',
                    name: '深圳市',
                    children: [
                        {
                            id:'111',
                            name: '南山区'
                        },
                        {
                            id:'112',
                            name: '福田区'
                        }
                    ]
                }
            ]
        }
    ]
    console.log(getp(list,'112'))
    function getp(list,value) {
        var arr = list.filter(() => true);
        var _pid;
        while (arr.length){
            var val = arr.shift();
            if(val.id === value){
                _pid = null;
            }else{
                if(val.children){
                    for(let i = val.children.length-1;i>=0;i--){
                        if(val.pid){
                            val.children[i].pid = val.pid.concat([val.id])
                        }else{
                            val.children[i].pid = [val.id]
                        }
                        if(val.children[i].id === value){
                            _pid = val.children[i].pid;
                            _pid.push(value)
                            arr = [];
                            break;
                        }
                        arr.push(val.children[i])
                    }
                }
            }
        }
        if(!_pid){
            console.log('没有父元素');
        }
        return _pid;
    }

xiaowuhero666 avatar Jul 29 '19 08:07 xiaowuhero666

const list =[
  {id:1,name:'部门A',parentId:0},
  {id:2,name:'部门B',parentId:0},
  {id:3,name:'部门C',parentId:1},
  {id:4,name:'部门D',parentId:1},
  {id:5,name:'部门E',parentId:2},
  {id:6,name:'部门F',parentId:3},
  {id:7,name:'部门G',parentId:2},
  {id:8,name:'部门H',parentId:4}
];

const convert = (list, filters) => {
  return list.map(item => {
    let children = filters.filter(child => child.parentId === item.id)
    if (children.length > 0) {
      return {
        ...item,
        children: convert(children, filters)
      }
    } else {
      return item
    }
  })
}

let res = convert(list, list)

wulichenyang avatar Jul 30 '19 02:07 wulichenyang

function findId(data,arr=[]) { for(let i=0;i<data.length;i++){ if(Object.keys(data[i]).includes('children')){ console.log(data[i]) arr.push(data[i].id) findId(data[i].children,arr) } } return arr; }

forever-Liudawang avatar Jul 30 '19 11:07 forever-Liudawang

const data = [{
  id: '1',
  name: 'test1',
  children: [
      {
          id: '11',
          name: 'test11',
          children: [
              {
                  id: '111',
                  name: 'test111',
              },
              {
                  id: '112',
                  name: 'test112'
              }
          ]

      },
      {
          id: '12',
          name: 'test12',
          children: [
              {
                  id: '121',
                  name: 'test121',
                  children: [
                    {
                      id: '1211',
                      name: 'test1211',
                    }
                  ]
              },
              {
                  id: '122',
                  name: 'test122'
              }
          ]
      }
  ]
}];

/**
 * 
 * @param {*} data 输入数据
 * @param {*} target 要找的id,默认它是全局唯一的
 * @param {*} route 当前路径
 * @param {*} depth 当前深度,route的长度要保持和它一样
 * @return 如果找到就返回路径,否则没有返回值
 */
function dfs(data, target, route, depth){
  for(let i=0; i<data.length; i++){
    // 要保持路径长度和当前深度一致
    if(route.length  > depth) {
      route = route.slice(0, depth);
    }
    route.push(data[i].id);
    let new_depth = depth + 1; // 深度已经加一,这个深度用于下一个dfs调用
    // console.log(new_depth, route); // 这个打印观察route的长度和new_depth的关系
    if(data[i].id == target) return route; // 如果找到了目标,就直接返回route
    if(data[i].children &&  data[i].children.length > 0){
      let res = dfs(data[i].children, target, route, new_depth);
      if(res) return res; // 如果递归的dfs找到了目标,返回递归dfs的返回值
    }
  }
}

/**
 * 每次都复制route,就不用记录depth
 * @param {*} data 
 * @param {*} target 
 * @param {*} route 
 */
function dfs2(data, target, route){
  for(let i=0; i<data.length; i++){
    let new_route = route.slice(); // 每次都复制之前的route
    new_route.push(data[i].id);
    if(data[i].id == target) return new_route; // 如果找到了目标,就直接返回route
    if(data[i].children &&  data[i].children.length > 0){
      let res = dfs2(data[i].children, target, new_route);
      if(res) return res; // 如果递归的dfs找到了目标,返回递归dfs的返回值
    }
  }
}

let t_list = ['1', '11', '12', '111', '112', '121', '122', '1211', '404'];
for(let i=0; i<t_list.length; i++){
  console.log(t_list[i], dfs(data, t_list[i], [], 0));
  console.log(t_list[i], dfs2(data, t_list[i], []));
}

BoatingZeng avatar Aug 02 '19 03:08 BoatingZeng

  const fn = (value, tree, newArr = []) => {
    function fn1 (tree) {
      if (value.startsWith(tree.id)) newArr.push(tree.id)
        if (tree.id === value || !tree.children) return
        for (const item of tree.children) {
          fn(value, item, newArr)
        }
    }
  
    if (tree instanceof Array) {
      for (const item of tree) fn1(item)
    }  else {
      fn1(tree)
    }

    return newArr
  }

  const tree = [{
    id: '1',
    name: '广东',
    children: [{
      id: '11',
      name: '深圳',
      children: [{
          id: '111',
          name: '南山区'
        },
        {
          id: '112',
          name: '福田区'
        }
      ]
    }]
  }]

  console.log(fn('112', tree))

dengshangli avatar Aug 02 '19 09:08 dengshangli

function fn(data, id) {
	const ref = []
	const dfs = function(data, id) {
		const quene = [...data]
        while(quene.length > 0) {
            const current  = quene.shift()
            if(current.id === id){
                return ref.concat(current.id)
            } else if(current.children) {
                ref.push(current.id)
                return dfs(current.children, id)
            }
        }
        return undefined
	}
	return dfs(data, id)
}

ZakZheng avatar Aug 03 '19 09:08 ZakZheng

    let res = [];
    let arr = [];
    const findId = (data, id) => {
      data.forEach((item, index) => {
        if (item.children) {
          if (item.id !== id) {
            res.push(item.id);
            findId(item.children, id);
          }
        }
        arr.push(item.id);
      })
      arr.includes(id) === true ? res : res = [];
      return res;
    }

SuAgnes avatar Aug 05 '19 14:08 SuAgnes

let func = function (value) { let newArr = []; let markAll = function (params, id) { params.forEach((i) => { if (i.children) { i.m_id = id markAll(i.children, i.id) } else { i.m_id = id } }) } markAll(data, undefined);//标记父级

        let find = function (opt, upId) {
            opt.forEach((i) => {
                if (i.id === upId) {
                    newArr.unshift(i.id)
                    find(data, i.m_id)
                } else {
                    if (i.children) {
                        find(i.children, upId)
                    }
                }
            })
        }
        find(data, value);// 调用查找父级
        return newArr;
    }

   console.log( func(112));

opacity-m avatar Aug 11 '19 09:08 opacity-m

class format {
  constructor(data) {
    this.res = [];
    this.data = data;
    this.start(data);
  }

  start(data) {
    if(data instanceof Array) {
      data.forEach(i => {this.start(i)})
    }else if(data instanceof Object) {
      if(data.id) {
        this.res.push(data.id)
        delete data.id
      }
      Object.values(data).forEach(i => {this.start(i)});
    }else {
      return this.res;
    }
  }
}
const data = [{
    id: '1',
    name: 'test1',
    children: [
        {
            id: '11',
            name: 'test11',
            children: [
                {
                    id: '111',
                    name: 'test111'
                },
                {
                    id: '112',
                    name: 'test112'
                }
            ]

        },
        {
            id: '12',
            name: 'test12',
            children: [
                {
                    id: '121',
                    name: 'test121'
                },
                {
                    id: '122',
                    name: 'test122'
                }
            ]
        }
    ]
}];
console.log(new format(data).res)
// ["1", "11", "111", "112", "12", "121", "122"]

zjjjjjjjjjjd avatar Aug 12 '19 11:08 zjjjjjjjjjjd

function Recursive_Path(data, value, path){ for( let i = 0; i< data.length; i++ ){ if(data[i].name === value){ return path.concat(data[i].id); }else{ if(data[i].children){ let child = data[i].children; let temp = path.concat(data[i].id); let result = Recursive_Path(child, value, temp); if(result) return result; else continue; }else{ continue; } } } }

let result = Recursive_Path(data, "test112", []);

my-illusion avatar Aug 14 '19 02:08 my-illusion

function find(tree, value) {
    var res;
    if(findFathers(tree, value)){
        return res;
    }
    else{
        return undefined;
    }
    function findFathers(tree, value, stuck) {
        stuck = stuck || [];
        for (let child of tree) {
            stuck.push(child.id);
            if (child.id === value) {
                //console.log(stuck);
                res = stuck.slice();
                return true;
            }
            if (child.children) {
                if (findFathers(child.children, value, stuck)) {
                    return true;
                }
            }
            stuck.pop();
        }
        return false;
    }
}

zzNire avatar Aug 14 '19 08:08 zzNire

  • bfs利用队列实现,循环中做的是push => shift => push => shift
  • dfs利用栈实现,循环中做的是push => pop => push => pop

刚刚好,中间仅仅差了一个数组方法:

function bfs(target, id) {
  const quene = [...target]
  do {
    const current = quene.shift()
    if (current.children) {
      quene.push(...current.children.map(x => ({ ...x, path: (current.path || current.id) + '-' + x.id })))
    }
    if (current.id === id) {
      return current
    }
  } while(quene.length)
  return undefined
}

function dfs(target, id) {
  const stask = [...target]
  do {
    const current = stask.pop()
    if (current.children) {
      stask.push(...current.children.map(x => ({ ...x, path: (current.path || current.id) + '-' + x.id })))
    }
    if (current.id === id) {
      return current
    }
  } while(stask.length)
  return undefined
}

// 公共的搜索方法,默认bfs
function commonSearch(target, id, mode) {
  const staskOrQuene = [...target]
  do {
    const current = staskOrQuene[mode === 'dfs' ? 'pop' : 'shift']()
    if (current.children) {
      staskOrQuene.push(...current.children.map(x => ({ ...x, path: (current.path || current.id) + '-' + x.id })))
    }
    if (current.id === id) {
      return current
    }
  } while(staskOrQuene.length)
  return undefined
}

为啥要返回undefined?

montage-f avatar Aug 15 '19 07:08 montage-f

function getListLinksById(list, id) { const linkMap = {}; list = JSON.parse(JSON.stringify(list)); function _initLink(obj, parentIds) { obj.link = [...parentIds, obj.id]; linkMap[obj.id] = obj.link; if (Array.isArray(obj.children)) { obj.children.forEach(child => _initLink(child, obj.link)); } } list.forEach(item => _initLink(item, [])); return linkMap[id]; } console.log(getListLinksById(list, '111'));

ShaoGuanHotel avatar Aug 19 '19 06:08 ShaoGuanHotel

const data = [{
    id: '1',
    name: '广东省',
    children: [
        {
            id: '11',
            name: '深圳市',
            children: [
                {
                    id: '111',
                    name: '南山区',
                    children: [
                        {
                            id: '115',
                            name: '未知'
                        }
                    ]
                },
                {
                    id: '112',
                    name: '福田区'
                }
            ]
        },
        {
            id: '12',
            name: '深圳市',
            children: [
                {
                    id: '113',
                    name: '南山区'
                },
                {
                    id: '114',
                    name: '福田区'
                }
            ]
        }
    ]
}];

/**
 * 获取目标id的路径
 * @param {string} target 查找目标id
 * @param {array} arr 当前进行查找遍历的数据
 * @param {array} path 当前路径
 * @param {object} result
 */
const getPath = (target, arr, path, result) => {
    for (let i = 0; i < arr.length; i++) {
        const item = arr[i];

        if (result.result) return

        if (item.id === target) {
            path.push(item.id)
            result.result = path;
            return
        }

        if (item.children && Array.isArray(item.children)) {
            const curPath = [...path];
            curPath.push(item.id);
            getPath(target, item.children, curPath, result)
        }
    }
}

const fn = value => {
    const result = {
        result: null
    };
    getPath(value, data, [], result)
    console.log(result.result)
}

fn('112') // => [ '1', '11', '112' ]
fn('115') // => [ '1', '11', '111', '115' ]
fn('114') // => [ '1', '12', '114' ]

GreyMiracle avatar Aug 21 '19 09:08 GreyMiracle

再发一个吧,这才是递归的合理使用方案

const data = [{
    id: '1',
    name: '广东省',
    children: [
        {
            id: '11',
            name: '深圳市',
            children: [
                {
                    id: '111',
                    name: '南山区',
                    children: [
                        {
                            id: '115',
                            name: '未知'
                        }
                    ]
                },
                {
                    id: '112',
                    name: '福田区'
                }
            ]
        },
        {
            id: '12',
            name: '深圳市',
            children: [
                {
                    id: '113',
                    name: '南山区'
                },
                {
                    id: '114',
                    name: '福田区'
                }
            ]
        }
    ]
}];

/**
 * 获取目标id的路径
 * @param {string} target 查找目标id
 * @param {array} arr 当前进行查找遍历的数据
 */
const getPath = (target, arr) => {
    for (let i = 0; i < arr.length; i++) {
        const item = arr[i];

        if (item.id === target) {
            return item.id
        }

        if (item.children && Array.isArray(item.children)) {
            const nextId = getPath(target, item.children);
            if (nextId) {
                return item.id + '|' + nextId
            }
        }
    }
}

const fn = value => {
    const strResult = getPath(value, data);
    const result = strResult.split('|');
    console.log(result)
}

fn('112') // => [ '1', '11', '112' ]
fn('115') // => [ '1', '11', '111', '115' ]
fn('114') // => [ '1', '12', '114' ]

GreyMiracle avatar Aug 21 '19 10:08 GreyMiracle

简单的回溯,用一个数组记录路径,在触达目标id时结束算法,此时算法走过的路径就是所有父级路径

//假设输入的id是正确的
function fn(id) {
    let res, choices = arr, search_done = false;
    bt([], choices);
    function bt(trace, choices) {
        if (search_done) return;//达到目的后应该终止回溯
        if (trace[trace.length - 1] === id) { //终止条件:路径中最后一个id就是目标id
            res = [...trace];//记得拷贝trace再赋值,因为路径可能还会被重写
            search_done = true;//目的达成,标记一下,不再继续搜索
        }
        else {
            for (let i in choices) {
                trace.push(choices[i].id);//前进一步
                bt(trace, choices[i].children)
                trace.pop();//后退一步
            }
        }
    }
    return res;
}


//demo:
let arr = [
    {
        id: 1,
        name: "广东",
        children: [
            {
                id: 11,
                name: "深圳市",
                children: [
                    {
                        id: 111,
                        name: "南山区"
                    },
                    {
                        id: 112,
                        name: "福田区"
                    }
                ]
            }, {
                id: 12,
                name: "广州市",
                children: [
                    {
                        id: 121,
                        name: "xxx"
                    },
                    {
                        id: 122,
                        name: "aaa"
                    }
                ]
            },
            {
                id: 13,
                name: "广州市2",
                children: [
                    {
                        id: 131,
                        name: "xxx2"
                    },
                    {
                        id: 132,
                        name: "aaa2"
                    }
                ]
            }
        ]
    }
];
console.log(fn(131))

DarthVaderrr avatar Aug 26 '19 06:08 DarthVaderrr

function fn (list, id) {
    function _fn (nodeList) {
        for (let i = 0, len = nodeList.length; i < len; i++) {
            const node = nodeList[i]
            if (node.id == id) {
                return [node.id]
            }
            if (node.children && node.children.length) {
                const r = _fn(node.children)
                if (r) {
                    return [node.id].concat(r)
                }
            }
        }
    }
    return _fn(list)
}

qq89987112 avatar Sep 03 '19 15:09 qq89987112

基于递归的DFS,本身就是一种调用栈,在每个调用栈中,保存当前栈元素,再根据给定的value作对比决定继续递归查找还是中断递归。注意递归的中断逻辑,和每个调用栈元素的保存

const data = [{
  id: "1",
  name: "test1",
  children: [
    {
      id: "11",
      name: "test11",
      children: [
        {
          id: "111",
          name: "test111"
        },
        {
          id: "112",
          name: "test112"
        }
      ]
    },
    {
      id: "12",
      name: "test12",
      children: [
        {
          id: "121",
          name: "test121"
        },
        {
          id: "122",
          name: "test122"
        }
      ]
    }
  ]
}];

function fn (value) {
  const result = [];
  const dfs = (source) => {
    for (let item of source) {
      result.push(item);
      if (item.id === value) {
        return;
      } else {
        const res = dfs(item.children || []);
        if (!res) return;
      }
      result.pop(item);
    }
    return true;
  };
  dfs(data);
  return result.map(item => item.id);
}
fn("112") // ["1", "11", "112"]

dione2017 avatar Sep 11 '19 09:09 dione2017

let list = [{
    id: 1,
    name: "广东省",
    children: [
        {
            id: 11,
            name: "深圳市",
            children: [
                {
                    id: 111,
                    name: "南山区",
                    children: [
                        {
                            id: 110,
                            name: "沙河派出所",
                            children: [
                                {
                                    id: 1101,
                                    name: "世界之窗",
                                }
                            ]
                        }
                    ]
                },
                {
                    id: 112,
                    name: "福田区"
                },
            ]
        },
        {
            id: 22,
            name: "广州市",
            children: [
                {
                    id: 114,
                    name: "越秀区"
                }
            ]
        }
    ]
},
{
    id: 3,
    name: "北京市",
    children: [
        {
            id: 31,
            name: "直辖区",
            children: [
                {
                    id: 311,
                    name: "东城区"
                },
                {
                    id: 312,
                    name: "西城区"
                }
            ]
        }
    ]
}];

const value = '112'
const fn = (value) => {
    let arr = [[]];
    let arrFloor = [];
    let searchArr = [];
    function parent(val) {
        for (let i in val) {
            if (!val[i].children) {
                arrFloor.push([val[i].id]);
            } else {
                children(val[i], val[i].id).pop();
            }
        }
        return arr.concat(arrFloor);
    };
    function children(val, id) {
        for (let i in val.children) {
            arr[arr.length - 1].push(val.id);
            if (arr[arr.length - 1][0] !== id) {
                arr[arr.length - 1].unshift(id)
            }
            if (val.children[i].children) {
                children(val.children[i], id)
                arr[arr.length - 1].splice(0, 1);
            } else {
                arr[arr.length - 1].push(val.children[i].id);
                arr.push([])
            }
        }
        return arr;
    }
    function searchFn(arr) {
        arr.map(res => {
            if (res.toString().indexOf(value) !== -1) {
                searchArr = res;
            }
        })
        return searchArr
    }
    return searchFn(parent.call(this, list));
}
fn(value) // 输出 [1, 11, 112]

yaodongyi avatar Sep 17 '19 10:09 yaodongyi

const data = [{
    id: '1',
    name: 'test1',
    children: [
        {
            id: '11',
            name: 'test11',
            children: [
                {
                    id: '111',
                    name: 'test111'
                },
                {
                    id: '112',
                    name: 'test112'
                }
            ]
        },
        {
            id: '12',
            name: 'test12',
            children: [
                {
                    id: '121',
                    name: 'test121'
                },
                {
                    id: '122',
                    name: 'test122'
                }
            ]
        }
    ]
}];


const fn = (value, list) => {
    let res = [];
    const loop = (data, temp = []) => {
        for (item of data) {
            if (item.id === value)
                res = [...temp, item.id];
            else {
                if (item.children)
                   loop(item.children, [...temp, item.id]);
            }
        }
    }
    loop(list);
    return res;
}  
fn('112', data);  // ["1", "11", "112"]

qianwen155 avatar Oct 08 '19 07:10 qianwen155

const findParent = (arr, idValue) => { const recursion = function(arr, index, parent) { const { child, id } = arr[index]; if (id == idValue) { let chain = parent + "," + id; chain = chain.substr(1, chain.length - 1); console.log("找到了", chain); return true; } if (child && recursion(child, 0, parent + "," + id)) { return true; } if (++index && arr.length > index && recursion(arr, index, parent)) { return true; } return false; }; recursion(arr, 0, ""); }; findParent(myArr, 232); findParent(myArr, 41); findParent(myArr, 13);

caihaihong avatar Oct 09 '19 02:10 caihaihong

const data = [{
    id: '1',
    name: 'test1',
    children: [
        {
            id: '11',
            name: 'test11',
            children: [
                {
                    id: '111',
                    name: 'test111'
                },
                {
                    id: '112',
                    name: 'test112'
                }
            ]
        },
        {
            id: '12',
            name: 'test12',
            children: [
                {
                    id: '121',
                    name: 'test121'
                },
                {
                    id: '122',
                    name: 'test122'
                }
            ]
        }
    ]
}];


const fn = (value, list) => {
    let res = [];
    const loop = (data, temp = []) => {
        for (item of data) {
            if (item.id === value)
                res = [...temp, item.id];
            else {
                if (item.children)
                   loop(item.children, [...temp, item.id]);
            }
        }
    }
    loop(list);
    return res;
}  
fn('112', data);  // ["1", "11", "112"]

大佬 加个break 感觉好点

const findParent1 = (myArr, idValue) => {
  let res;
  const recursion1 = function(myArr, temp = []) {
    for (let item of myArr) {
      if (res) break;
      const { id, child } = item;
      if (id == idValue) {
        res = [...temp, id];
        break;
      }
      if (child) {
        recursion1(child, [...temp, id]);
      }
    }
  };
  recursion1(myArr, []);
  return res;
};
findParent1(myArr, 11);

caihaihong avatar Oct 09 '19 03:10 caihaihong

// 原始 list 如下 let arr = [ { id: 1, name: "广东", children: [ { id: 11, name: "深圳市", children: [ { id: 111, name: "南山区" }, { id: 112, name: "福田区" } ] }, { id: 12, name: "广州市", children: [ { id: 121, name: "xxx" }, { id: 122, name: "aaa" } ] }, { id: 13, name: "广州市2", children: [ { id: 131, name: "xxx2" }, { id: 132, name: "aaa2" } ] } ] } ]; let solve = function (arr,list) { for(let item of list){ arr.push({ id: item.id, name: item.name, parentId: item.parentId }); if (item.children) { solve(arr,item.children) } } return arr }

let find = function (list,id) {
    let obj = list.reduce(function (a,b) {
        a[b.id] = b
        return a
    },{});
    let rr = [];
    let fn = function (id) {
        rr.push(id)
        if (obj[id].parentId!==0) {
            fn(obj[id].parentId);
        }
    }
    fn(id)
    return rr
}

console.log(    find(solve([],arr),8))

2384830985 avatar Oct 17 '19 09:10 2384830985

  const value = '112'
  const list = [
      {
        id: '1',
        children: [
          {
            id: '11',
            children: [{
              id: '111'
            },{
              id: '112'
            }]
          }
        ]
      },
      {
        id: '2',
        children: [
          {
            id: '112'
          }
        ]
      }
    ]

  const fn = (value) => {
    // 获取所有的路径
    let res = []
    const innerFunc = (node ,arr) => {
      arr.push(node.id)
      if (node.id === value) {
        res.push(arr)
      }
      if (node.children) {
        for (let i = 0; i < node.children.length; i++) {
          innerFunc(node.children[i], arr.slice())
        }
      }
    }
    for (let i = 0 ; i < list.length; i++) {
        innerFunc(list[i], [])
    }
    return res
  }
  fn('112')



aeolusheath avatar Oct 20 '19 08:10 aeolusheath

const data = [
  {
    id: '1',
    name: 'test1',
    children: [
      {
        id: '11',
        name: 'test11',
        children: [
          {
            id: '111',
            name: 'test111'
          },
          // {
          //   id: '112',
          //   name: 'test112'
          // }
        ]
      },
      {
        id: '12',
        name: 'test12',
        children: [
          {
            id: '121',
            name: 'test121'
          },
          {
            id: '122',
            name: 'test122'
          }
        ]
      }
    ]
  },
  {
    id: '2',
    name: 'test2',
    children: [
      {
        id: '112',
        name: 'test112'
      }
    ]
  }
]

const value = '112'
const fn = (value) => {
  let tree = []

  /**
   * |----1----|----2----|----3----|
   * =push=>   =push=>   =push=>
   * <=pop=   <=pop=   <=pop=
   */
  function find (arr, value) {
    for (let i = 0; i < arr.length; i++) {
      const e = arr[i];
      const id = e.id

      if (id === value) {
        tree.push(id)
        console.log(tree)
        break
      } else {
        if (e.children) {
          tree.push(id)
          find(e.children, value)
          // 判断子级是否有,有则中断父级
          if (tree.includes(value)) break
        }
        // 退出当前的层级
        if (i + 1 === arr.length) tree.pop()
      }
    }
  }
  find(data, value)

  console.log(tree)
}
fn(value) // 输出 [1, 11, 112]

JackFGreen avatar Oct 30 '19 06:10 JackFGreen

function getUrl(data, split = '') {
    let map = {}
    map = data.reduce(function (res, item) {
        if (item.children) {
            res = Object.assign(res, getUrl(item.children, split ? (split + ',' + item.id) : item.id))
        }
        item.url = split ? (split + ',' + item.id) : item.id;
        res[item.id] = item;
        return res
    }, {})
    return map
}
function find(data, val) {
    return getUrl(data)[val]['url']
}


console.log(find(data,'112'))

xml00007 avatar Nov 04 '19 12:11 xml00007

const data = [
    {
        id: 1,
        children: [
            {
                id: 2,
                children: [
                    {
                        id: 3,
                    },
                    {
                        id: 4,
                    },
                ],
            },
        ],
    },
];

// 思路:递归遍历,找到目标id后逐级将id返回
function find(id) {
    function each(items) {
        for (let item of items) {
            if (item.id === id) {
                return [id];
            }
            if (item.children && item.children.length) {
                const r = each(item.children);
                if (Array.isArray(r)) {
                    r.unshift(item.id);
                    return r;
                }
            }
        }
    }

    return each(data);
}

console.log(find(1)); // [1]
console.log(find(2)); // [1, 2]
console.log(find(3)); // [1, 2, 3]
console.log(find(4)); // [1, 2, 4]

kite3 avatar Nov 05 '19 03:11 kite3

const fn_12 = (value) => { const data = [ { id: 1, children: [ { id: 11, children: [ { id: 111 }, { id: 112 } ] } ] }, { id:2, children:[ { id:22, children:[{ id:222 }] }, { id:223, children:[ { id:2233, children:[ { id:223323 } ] }, { id:22334 } ] } ] } ] const fn_2 = (arr, ids) => arr.map((item) => { item.parentId = [...ids]; item.id === value && console.log(item.parentId); item.hasOwnProperty("children") && fn_2(item.children, [...item.parentId, item.id]); return item; }) fn_2(data,[]) } fn_12(223323)

Qujoe avatar Nov 06 '19 06:11 Qujoe

@GitHub官方 能不能加个代码校验功能?保证代码正确无误

wangjianleo avatar Nov 08 '19 03:11 wangjianleo

function findAncestors(value, list) {
    function find(list) {
        for (let i = 0; i < list.length; i++) {
            const item = list[i]
            let childrenId
            if (item.id === value) {
                return [item.id]
            } else if (item.children && (childrenId = find(item.children))) {
                return [item.id].concat(childrenId)
            }
        }
    }
    return find(list)
}

huangjieqiu avatar Nov 14 '19 06:11 huangjieqiu

const findTransIdToChildren = (data, id) => {
  let arr = null
  const find = (data, idArr = []) => {
    if (arr) return
    for (let i = 0; i < data.length; i++) {
      if (arr) return
      let inarr = idArr.concat(data[i].id)
      if (data[i].id === id) {
        arr = inarr
        finded = true
        return arr
      }
      if (data[i].children) {
        find(data[i].children, inarr)
      }
    }
  }
  find(data, [])
  return arr
}

maginapp avatar Nov 21 '19 09:11 maginapp

const findIds = (id, data) => {
    if (!findIds.ids) findIds.ids = []
    for (let item of data) {
        if (id === item.id) {
            findIds.ids.push(id)
            return findIds.ids
        }

        if (item.children && findIds(id, item.children).length) {
            findIds.ids.unshift(item.id)
            return findIds.ids
        }
    }

    return findIds.ids
}

yueshuiniao avatar Nov 26 '19 06:11 yueshuiniao

就不能有个正常点的?

const path = [];
function search(arr, val) {
  for (let i = 0; i < arr.length; i++) {
    path.push(arr[i].id);
    if (arr[i].id === val) {
      path.push(arr[i].id);
      return true;
    }
    if (arr[i].child) {
      if (search(arr[i].child, val) !== true) {
        path.pop();
      }
    }
  }
}
search(arr, 112);

Jmingzi avatar Nov 27 '19 03:11 Jmingzi

var log = console.log;

const data = [
  {
    id: '1',
    name: 'test1',
    children: [
      {
        id: '11',
        name: 'test11',
        children: [
          {
            id: '111',
            name: 'test111'
          },
          {
            id: '112',
            name: 'test112'
          }
        ]
      },
      {
        id: '12',
        name: 'test12',
        children: [
          {
            id: '121',
            name: 'test121'
          },
          {
            id: '122',
            name: 'test122'
          }
        ]
      }
    ]
  }
]

const res = []

function findVal(arr = [], val) {
  const len = arr.length
  for (let i = 0; i < len; i++) {
    if (arr[i].id == val || findVal(arr[i].children, val)) {
      res.push(arr[i].id)
      return true
    }
  }
  return false
}
findVal(data, '112')
log(res.reverse())

one-pack-stomach-man avatar Nov 28 '19 10:11 one-pack-stomach-man

需要查找的值为value,arr为原数组

// 需要查找的值
        const value = '212';
        // 返回的值
        let rel = []
        let val = fn(value, arr, order = []);
        function fn(value, arr, order) {
            for (let i = 0; i < arr.length; i++) {
                // 每次加入之前移除相邻节点
                order = order.filter(item => {
                    return !new Set(arr.filter(item =>{return item.id != arr[i].id}).map(item => item.id)).has(item)
                })
                // 清空节点之后加入新节点
                order.push(arr[i].id)
                // 没找到继续查找
                if (arr[i].id != value) {
                    if (arr[i].children) {
                        fn(value, arr[i].children, order)
                    }
                } else {
                    rel = [...order];
                }
            }
            return rel;
        }

fxxlsc avatar Nov 29 '19 08:11 fxxlsc

请问一下代码颜色样式怎么调呢

fxxlsc avatar Nov 29 '19 08:11 fxxlsc

请问一下代码颜色样式怎么调呢

one-pack-stomach-man avatar Dec 01 '19 14:12 one-pack-stomach-man

请问一下代码颜色样式怎么调呢

// ```javascript 
 code block
// ```

one-pack-stomach-man avatar Dec 01 '19 14:12 one-pack-stomach-man

谢谢

fxxlsc avatar Dec 02 '19 01:12 fxxlsc

const data = [{
    id: '1',
    name: 'test1',
    children: [
        {
            id: '11',
            name: 'test11',
            children: [
                {
                    id: '111',
                    name: 'test111'
                },
                {
                    id: '112',
                    name: 'test112'
                }
            ]

        },
        {
            id: '12',
            name: 'test12',
            children: [
                {
                    id: '121',
                    name: 'test121'
                },
                {
                    id: '122',
                    name: 'test122'
                }
            ]
        }
    ]
}];

// 是否出现了与目标 id 相等的值
let hasEqual = false

const findParentList = (arr, targetId, result = []) => {
  for (let item of arr) {

    result.push(item.id)

    if (Array.isArray(item.children)) {
      findParentList(item.children, targetId, result)
    }

    if (!hasEqual) {
      tail = result.pop()
    }
    
    if (tail === targetId) {
      hasEqual = true
      return result
    }
  }
}

let r = findParentList(data, '121', [])

console.log('r: ', r)

gauseen avatar Dec 06 '19 08:12 gauseen

来个不一样的, 先把树形数据扁平化, 再查找

      // 扁平化数据
      function getFlatData (data = [], flatData = {}, parentId) {
        data.forEach((item) => {
          const { children, ...rest } = item;
          flatData[item.id] = { ...rest, parentId };
          if (children) {
            getFlatData(children, flatData, item.id);
          }
        });
        return flatData;
      }

      // 找到parentId
      function findParentIds (id, data) {
        const flatData = getFlatData(data);

        const curData = flatData[id] || {};
        const result = [id];
        let { parentId } = curData;
        while (parentId) {
          const parentNode = flatData[parentId] || {};
          result.unshift(parentId);
          parentId = parentNode.parentId;
        }

        return result;
      }

soneway avatar Dec 25 '19 11:12 soneway

const value = '112'
const data = [{
  id: '1',
  name: 'test1',
  children: [
    {
      id: '11',
      name: 'test11',
      children: [
        {
          id: '111',
          name: 'test111'
        },
        {
          id: '112',
          name: 'test112'
        }
      ]

    },
    {
      id: '12',
      name: 'test12',
      children: [
        {
          id: '121',
          name: 'test121'
        },
        {
          id: '122',
          name: 'test122'
        }
      ]
    }
  ]
}]
const fn = (value) => {
  return find(data)
  function find(nodes) {
    if (!Array.isArray(nodes) || !nodes.length) {
      return
    }
    for (const node of nodes) {
      if (node.id === value) {
        return [node.id]
      }
      const r = find(node.children)
      if (r) {
        return [node.id, ...r]
      }
    }
  }
}
console.log(fn(value))// 输出 [1, 11, 112]


blank121 avatar Dec 29 '19 14:12 blank121

const data = [ {id: 5}, { id: 1, name: '广东省', children: [ { id: 11, name: '深证市', children: [ { id: 111, name: '南山区', children: [ {id: 1111} ] }, { id: 112, name: '福田区' }, ] }, { id: 12, children: [ {id: 13} ] } ] } ]

const fn = (value) => {
  let list = []
  const findItem = (children, arr) => {
    for (const item of children) {
      let newArr = [...arr]
      if (item.id === value) {
        list.push(...newArr,value)
      }

      if (list.length)
        return false
      if (item.children) {
        newArr.push(item.id)
        findItem(item.children, newArr)
      }
    }
  }
  findItem(data, list)
  return list
}

console.log(fn(1111))  // [1,11,111,1111]

wujh0010 avatar Jan 15 '20 09:01 wujh0010

function findParentsNode (data, id, arr = []) {
    if (!data || !id) return false
    for (let i = 0; i < data.length; i++) {
      let nodes = arr.concat([])
      nodes.push(data[i].id)
      if (data[i].id === id) {
        return nodes
      }
      if (data[i].children) {
        let res = findParentsNode(data[i].children || [], id, nodes)
        if (Array.isArray(res)) return res
      }
    }
}

Bigzo avatar Feb 06 '20 15:02 Bigzo

	function findId(data, value) {
		let ret = []
		function loop(data, temp = []) {
			for (let i = 0; i < data.length; i++) {
				if (data[i].id !== value) {
					if(data[i].children&&data[i].children.length){
						temp.push(data[i].id)
						loop(data[i].children,temp)
						temp.pop(data[i].id)
					}
				} else {
					temp.push(data[i].id)
					ret = temp.slice()
					throw "已找到..."
				}
			}
		}
		try {
			loop(data)
		} catch (error) {
		}
		return ret
	}

13866368297 avatar Mar 18 '20 10:03 13866368297

function grepObj(){
    let arr = [];
    return function grepRObj(obj,id){
        if(id == obj.id){
            return id
        }else{
            arr.push(obj.id);
            (obj.children || []).forEach(item=>{
                let _id = grepRObj.call(this,item,id);
                if(_id){
                    arr.push(_id);
                    console.log('arr => ',arr);
                }
                arr.pop();
            })
        }
    }
}

let fn = grepObj();

fn({
    id: '1',
    children: [{
        id: '11',
        children: [{
            id: '110',
            children:[{
                id:"1120"
            }]
        }, {
            id: '112'
        }]
    }, {
        id: '12',
        children: [{
            id: '1120'
        }, {
            id: '111'
        }]
    }]
},1120)

foolzhang avatar Mar 25 '20 13:03 foolzhang

/***
 * 思路:
 *      此题可对应 树-值为x的所有祖先
 *      本质是从根节点遍历到目标节点,记录路径的问题
 * 实现:
 *      后序遍历,弹栈的时候前插根节点
 *      时间复杂度:O(n) 空间O(n) 改为后序遍历的迭代实现的话空间可降至O(1)
 */
function fn(arr, targetId) {
    let result = [];
    let popRoot = false;
    fnCall(arr);
    return result;

    function fnCall(nodeArr) {
        if (!nodeArr || nodeArr.length === 0) return;

        for (let node of nodeArr) {
            if (node.id === targetId) {
                popRoot = true;
            }
            // 使用popRoot 为了不再继续向下递归 只要在某个结点找到了x值整个递归程序开启回溯模式 所以使用全局flag控制
            !popRoot && node.children && fnCall(node.children);
            popRoot && result.unshift(node.id);
        }
    }
}

更多数据结构经典题可移步https://github.com/EmilyYoung71415/StructuresandAlgorithms-Code ^.^ 求star 求交流

EmilyYoung71415 avatar Mar 28 '20 17:03 EmilyYoung71415

dfs

const fn = (data, value) => {
  let res = []
  const dfs = (arr, temp = []) => {
    for (const node of arr) {
      if (node.children) {
        dfs(node.children, temp.concat(node.id))
      } else {
        if (node.id === value) {
          res = temp
        }
        return
      }
    }
  }
  dfs(data)
  return res
}

为什么运行结果不对

代码有点问题,dfs中的return放到if里面就好了

JiangMengLei avatar Apr 13 '20 07:04 JiangMengLei

// 已知数据格式,实现一个函数 fn 找出链条中所有的父级 id
let list = [
	{
		id: 1,
		children: [
			{
				id: 2,
				children: [
					{
						id: 4,
					},
					{
						id: 112,
						children: [
							{
								id: 113,
							},
						],
					},
				],
			},
			{
				id: 3,
				children: [
					{
						id: 6,
					},
					{
						id: 7,
						children: [
							{
								id: 115,
							},
						],
					},
				],
			},
		],
	},
];

function p(data, key) {
	let arr = [];
	function _m(_arr, _key) {
		let _saveL = [];
		let _index = null;
		let _s = _arr.find((el, index) => {
			if (el.children) {
				el.children.forEach((element) => {
					element.parentid = index;
				});
				_saveL.push(...el.children);
			}
			if (el.id == _key) {
				_index = index;
				return true;
			}
		});
		if (!_s) {
			let obj = _m(_saveL, key);
			arr.unshift(_arr[obj].id);
			return _arr[obj].parentid;
		}
		arr.push(_s.id);
		return _s.parentid;
	}
	_m(data, key);
	return arr;
}

let a = p(list, '115');
console.log(a);

GTRgoSky avatar Apr 17 '20 09:04 GTRgoSky

const obj = [{ id: '1', name: '广东省', children: [{ id: '11', name: '深圳市', children: [{ id: '111', name: '南山区' }, { id: '112', name: '福田区' }] }] }]

const getIds = (obj, id) => {
    const dfs = (obj, stack = []) => {
        for(let item of obj) {
            stack.push(item);
            if (item.id === id) {
                return stack;
            } else {
                if (item.children && item.children.length) {
                    return dfs(item.children, stack);
                } else {
                    stack.pop(item);
                }
            }
        }
    }
    return dfs(obj).map(item => item.id);
}

console.log(getIds(obj, '112'));

xiaochen-01 avatar Apr 22 '20 11:04 xiaochen-01

深度优先遍历,遍历的时候得到每个node的父ids,最后再遍历一次拿到父 ids

const data = [{
    id: '1',
    name: 'test1',
    children: [
        {
            id: '11',
            name: 'test11',
            children: [
                {
                    id: '111',
                    name: 'test111'
                },
                {
                    id: '112',
                    name: 'test112'
                }
            ]

        },
        {
            id: '12',
            name: 'test12',
            children: [
                {
                    id: '121',
                    name: 'test121'
                },
                {
                    id: '122',
                    name: 'test122'
                }
            ]
        }
    ]
}];

function fn(parentId, nodeList) {
  let nodes = []
  if(nodeList) {
    nodeList.forEach(node => {
      nodes.push({
        name: node.name,
        id: node.id,
        parentId: parentId
      })
      if(node.children) {
        const pId = parentId ? parentId + '-'+ node.id : node.id
        nodes = nodes.concat(fn(pId, node.children))
      }
    })
  }
  return nodes  
}

function find(value) {
  const nodes = fn(null, data)
  
  const currentNode = nodes.find(item => item.id === value)
  
  const ids = [...currentNode.parentId.split('-'), currentNode.id]
  console.log(ids)
}

find('121')

yangjiedage avatar Apr 29 '20 06:04 yangjiedage

function findIds(list, value) {

    return dfs(list, value);
}

function dfs(list, value) {
    const stack = [...list];

    while (stack.length) {

        const cur = stack.pop();

        // 找到目标节点,递归结束
        if (cur.id === value) {
            return [cur.id];
        } else if (cur.children && cur.children.length) {
            const res = dfs(cur.children, value);

            if (res) {
                return [cur.id, ...res]
            }
        }

    }
}

const value = '112';

console.log(findIds(data, value));

fengmiaosen avatar May 09 '20 11:05 fengmiaosen

const data = [{ id: '1', name: 'test1', children: [ { id: '11', name: 'test11', children: [ { id: '111', name: 'test111' }, { id: '112', name: 'test112' } ]

    },
    {
        id: '12',
        name: 'test12',
        children: [
            {
                id: '121',
                name: 'test121'
            },
            {
                id: '122',
                name: 'test122'
            }
        ]
    }
]

}]; const fn = (data,vule)=>{ let res = [] const dfs = (arr,temp = []) =>{ for(const node of arr){ if(node.id === vule){ // 如果该节点就是 temp.push(node.id) res = temp return }else{ // 继续搜索 if(node.children){ dfs(node.children,temp.concat(node.id)) }
} } } dfs(data) return res } console.log(fn(data,'11'))

FFFangYu avatar May 27 '20 01:05 FFFangYu


var list = [{
    id: '1',
    children: [{
        id: '11',
        children: [{
            id: '111'
        }, {
            id: '112'
        }]
    }, {
        id: '12',
        children: [{
            id: '121'
        }, {
            id: '122'
        }]
    }]
}]
const res = [];

function find(list, value, parent) {
    for (let i = 0; i < list.length; i++) {
        if (parent) {
            list[i].parent = parent;
        }
        if (list[i].id === value) {
            let p = list[i];
            while (p) {
                res.push(p.id);
                p = p.parent;
            }
            break;
        }
        if (list[i].children) {
            find(list[i].children, value, list[i])
        }
    }

}

const value = '121';

find(list, value)
console.log(res.reverse())

yuanxiang1990 avatar Jul 04 '20 08:07 yuanxiang1990

const data = [{
    id: '1',
    name: 'test1',
    children: [
        {
            id: '11',
            name: 'test11',
            children: [
                {
                    id: '111',
                    name: 'test111'
                },
                {
                    id: '112',
                    name: 'test112'
                }
            ]

        },
        {
            id: '12',
            name: 'test12',
            children: [
                {
                    id: '121',
                    name: 'test121'
                },
                {
                    id: '122',
                    name: 'test122'
                }
            ]
        }
    ]
}];

function fn(id, arr) {
    let target = []
    function rfn(finArr, cArr = []) {
        let newArr = [...cArr]
        if (finArr instanceof Array) {
            finArr.find(item => {
                if (item.id === id) {
                    target = [...newArr, item.id]
                    return true
                } else {
                    if (item.children) {
                        rfn(item.children, [...newArr, item.id])
                        if (target.length > 0) {
                            return true
                        }
                    } else {
                        return false
                    }

                }
            })
        }
    }
    rfn(arr)
    return target

}

console.log(fn('112', data));

不知道这样可以不
思路是每次遍历之前都利用结构记录一下层级,如果知道对应的id,直接返回即可

yjfhtop avatar Jul 20 '20 03:07 yjfhtop

var searched = [];
var stack = [];
var has = false;
var id = '24';
function DFS(arr) {
  //深度遍历
  if (isEnd(arr)) {
    if (arr.id == id) {
      return true;
    } else {
      stack.pop();
    }
  }
  for (var i = 0; i < arr.child.length; i++) {
    var node = arr.child[i];
    if (has) {
      break;
    }
    if (!searched.includes(node.id)) {
      searched.push(node.id);
      stack.push(node.id);
      if (DFS(node)) {
        has = true;
        return stack;
      }
    }
  }
  return stack;
}
function isEnd(arr) {
  if (!arr.child || arr.id == id) {
    return true;
  }
}

wang-qiqi avatar Jul 20 '20 07:07 wang-qiqi

`const list = [{ id: '1', name: '广东省', children: [{ id: '11', name: '深圳市', children: [{ id: '111', name: '南山区' }, { id: '112', name: '福田区' } ] }] }]

const value = '112' const fn = (value, list) => { let queue = [...list], res = [], level = 0 while(queue.length) { debugger let length = queue.length for (let i = 0; i < length; i++) { let node = queue.shift() if (node.id === value) { res.push(node.id) } else { if (value.slice(0, level + 1) === node.id) { res.push(node.id) } node.children && queue.push(...node.children) } } level++ }

return res

} console.log(fn(value, list))`

广度优先遍历

KGKAI avatar Aug 02 '20 03:08 KGKAI

@wangyuanyuan0521 @ZodiacSyndicate

function fn(data, value) {
  let res = []
  const dfs = (arr, temp = []) => {
    for (const node of arr) {
      if (node.id === value) {
        res = temp
        return
      } else {
        node.children && dfs(node.children, temp.concat(node.id))
      }
    }
  }
  dfs(data)
  return res
}

if (node.id === value) { temp.push(node.id) res = temp return }

leehomeok avatar Aug 03 '20 12:08 leehomeok

var value = '112'
let res = []
function fn(data, temp = []) {
  for(node of data) {
    if(node.id === value) {
	res = temp
	break
     }
     if(node.children) {
	fn(node.children, [...temp, ...[node.id]])
     } 
   }
  return [...res, ...[value]]
}

huangpeng0428 avatar Aug 04 '20 06:08 huangpeng0428

// 回溯
function fn(list, value) {
  let res = []
  function helper(list, node) {
    if (node.id === value) {
      res = [...list]
      return
    }
    if (!node.children || !node.children.length) {
      return
    }
    for (let item of node.children) {
      list.push(item.id)
      helper(list, item)
      list.pop()
    }
  }
  helper([], {children:list})
  return res
}

wabRul avatar Sep 03 '20 09:09 wabRul

function findFather(list, targetId, path = []) {
        const len = list.length;
        for (let i = 0; i < len; i++) {
          console.log(list[i].id);
          if (list[i].id === targetId) {
            path.push(targetId);
            break;
          } else if (list[i].children) {
            path.push(list[i].id);
            findFather(list[i].children, targetId, path);
          } else if (list[i].id !== targetId && i === len-1) {
            path.pop();
          }
        }
        return path;
      }

Vitaminaq avatar Sep 17 '20 03:09 Vitaminaq

const info = [{ id: '1', name: '广东省', children: [{ id: '11', name: '深圳市', children: [{ id: '111', name: '南山区', }, { id: '112', name: '福田区' }] }] }]; const fn = (value) => { let res = null; const dfs = (data, path) => { data.forEach((item) => { if (item.id === value) { path.push(item.id); res = path; return; }; if (item.children) { path.push(item.id); dfs(item.children, path); } }); }; dfs(info, []); return res; };

hanhang123 avatar Nov 16 '20 14:11 hanhang123

`var list = [{ id: '1', children: [{ id: '11', children: [{ id: '111' }, { id: '112' }] }, { id: '12', children: [{ id: '121' }, { id: '122' }] }] }]

let result = []; function findParentId(list2, val) { for (let key of list2) { console.log(key) if (key.id === val) { result.push(key.id); return result; } if (key.children) { result.push(key.id); let re = findParentId(key.children, val); if (re && re.length) { return re; } else { result.pop(); }`

usernameGao avatar Dec 17 '20 10:12 usernameGao

function findId(list) {
    let arr = []
    list.map(item => {
        arr.push(item.id)
        item.children && arr.push(findId(item.children))
    })
    return arr.flat(10)
}

JeremyChenn avatar Jan 10 '21 09:01 JeremyChenn

function fnBFS(list, target) { let resMap = {}

let queue = []
let map = {}
list.forEach(item => {
    queue.push(item)
    map[item.id] = true
})
while(queue.length) {
    let item = queue.shift()
    if(item.children) {
        for(child of item?.children) {
        if(!map[child.id]) {
            queue.push(child)
            map[child.id] = true
            resMap[child.id] = item.id
        }
    }    
    }
}

console.log(resMap) let res = '' while(resMap[target]) { res += ${target} -> target = resMap[target] if(!resMap[target]) { res += target } }

console.log(res) }

DIVINER-onlys avatar Feb 07 '21 03:02 DIVINER-onlys

const data = [{
            id: '1',
            children: [{
                id: '11',
                children: [{
                    id: '111'
                }, {
                    id: '112'
                }]
            }, {
                id: '12',
                children: [{
                    id: '121'
                }, {
                    id: '122'
                }]
            }]
        },{
            id: '2',
            children: [{
                id: '21',
                children: [{
                    id: '211'
                }, {
                    id: '212'
                }]
            }, {
                id: '22',
                children: [{
                    id: '221'
                }, {
                    id: '222'
                }]
            }]
        }]
        //递归+some(匹配到值结束)
        function findIdList(data,id,parent) {
            const has = data.some(item=>{
                item.value = parent?[...parent.value,item.id]:[item.id]
                if(item.id === id){
                    findIdList.value = item.value
                    return true
                }
                if(item.children){
                    return findIdList(item.children,id,item)
                }
            })
            if(has){
                return findIdList.value
            }
        }
        const result = findIdList(data,"222")
        console.log(result);

13866368297 avatar Feb 10 '21 02:02 13866368297

前缀树 Trie,复杂度仅为需要查找value的长度:

    class Node {
      constructor(isWord = false) {
        this.isWord = isWord;
        this.next = new Map();
      }
    }

    class Trie {
      constructor() {
        this.root = new Node();
      }
      add(key) {
        let cur = this.root;
        for (let i = 0; i < key.length; i++) {
          const c = key[i];
          if (!cur.next.get(c)) {
            cur.next.set(c, new Node());
          }
          cur = cur.next.get(c);
        }
      }
      match(prefix) {
        if (prefix === "") {
          return [];
        }
        let cur = this.root;
        const res = [];
        for (let i = 0; i < prefix.length; i++) {
          const c = prefix[i];
          if (!cur.next.get(c)) {
            return [];
          }
          res.push(prefix.slice(0, i + 1));
          cur = cur.next.get(c);
        }
        return res;
      }
    }

    const trie = new Trie();
    function add(address) {
      for (let i = 0; i < address.length; i++) {
        trie.add(address[i].id);
        if (address[i].children) {
          add(address[i].children);
        }
      }
    }
    add(address);
    trie.match("112"); // [1,11,112]
    trie.match("111"); // [1,11,111]
   trie.match("11"); // [1,11]
   trie.match("110"); // []

huxiaocheng avatar Feb 21 '21 16:02 huxiaocheng

const data = [{
  id: '1',
  name: 'test1',
  children: [
      {
          id: '11',
          name: 'test11',
          children: [
              {
                  id: '111',
                  name: 'test111'
              },
              {
                  id: '112',
                  name: 'test112'
              }
          ]

      },
      {
          id: '12',
          name: 'test12',
          children: [
              {
                  id: '121',
                  name: 'test121'
              },
              {
                  id: '122',
                  name: 'test122'
              }
          ]
      }
  ]
}];

// 通过递归来实现
function find(arr, value) {
  const result = [];
  for(let i = 0; i < arr.length; i++) {
    const item = arr[i];
    if(item.id === value) {
      return [value]
    }

    if(item.children) {
      const ids = find(item.children, value);
      if(ids.length > 0) {
        result.push(item.id, ...ids);
      }
    }
  }
  return result;
}

console.log(find(data, '11'));

Minzax avatar Feb 24 '21 07:02 Minzax

const data = [
  {
    id: "1",
    name: "test1",
    children: [
      {
        id: "11",
        name: "test11",
        children: [
          {
            id: "111",
            name: "test111"
          },
          {
            id: "112",
            name: "test112"
          }
        ]
      },
      {
        id: "12",
        name: "test12",
        children: [
          {
            id: "121",
            name: "test121"
          },
          {
            id: "122",
            name:
              "test122"
          }
        ]
      }
    ]
  }
]

function find(arr, value) {
  let map = new Map()
  recursion(arr, [], map)
  console.log(map)
  return map.get(value);
}
function recursion(arr, parentArr, map) {
  arr.forEach(item => {
    let _parentArr = parentArr.slice()
    _parentArr.push(item.id)
    map.set(item.id, _parentArr);
    if (item.children && item.children.length > 0) {
      recursion(item.children, _parentArr, map)
    }
  })
}

console.log(find(data, '122'))

865077695 avatar Mar 10 '21 03:03 865077695

let list = [{ id: '1', value: '四川省', children: [{ id: '11', value: '成都市', children: [{ id: '111', value: '高新区' }, { id: '112', value: '天府新区' }] }] }, { id: '2', value: '四川省', children: [{ id: '21', value: '成都市', children: [{ id: '211', value: '高新区' }, { id: '212', value: '天府新区' }] }] }];

function fn(list, id) { let res = []

function search(list, res) { let searched = false; for (let node of list) { if (node.id === id) { res.push(node.id) return true } else { if (node.children) { res.push(node.id) searched = search(node.children, res); if (searched) { return true } } } } if (!searched) { res.pop() return false } }

search(list, res); return res }

console.log(fn(list, '212'))

chengduHe avatar Mar 18 '21 07:03 chengduHe