js树结构--过滤数据(查找,筛选)

这篇博客介绍了如何使用JavaScript实现树结构数据的过滤和查找功能,通过递归遍历每个节点,当节点的title1属性包含指定值时,将其与子节点一并保留。代码中展示了如何构建新的过滤后的数据列表,并在控制台输出了处理过程。

树结构过滤(查找)数据,父级一起带出来。

搜索到的结果 

树形结构数据的高效过滤与父级关联方案 

问题场景:树形数据的智能搜索

在实际开发中,我们经常需要处理树形结构数据的搜索过滤,并且要求能够同时返回匹配节点及其所有父级节点。这种需求在文件系统、组织架构、分类目录等场景中十分常见。本文将深入分析一个树形数据过滤方案,并提供多种优化思路。

基础实现方案分析

直接上代码。。。。

/**
   * @author 过滤数据
   * @param {*} value
   * @param {*} arr
   * @return {*} []
   */
  const TreeDataList = (value:any = '', arr:any) => {
    if (!arr) {
      return []
    }
    let newList:any[] = [];
    arr.forEach((item:any) => {
      if (item.title1.indexOf(value) > -1) {
        const Children = TreeDataList(value, item.children);
        const obj = {
          ...item,
          children: Children
        }
        console.log(item,obj,Children);
        newList.push(obj);
      } else {
        if (item.children && item.children.length > 0) {
          const Children = TreeDataList(value, item.children);
          const obj = {
            ...item,
            children: Children
          };
          if (Children && Children.length > 0) {
            newList.push(obj);
          }
        }
      }
    });
    return newList;
  };

当前实现特点:

  1. 递归遍历树形结构

  2. 匹配包含关键词的节点(title1)

  3. 自动保留有效子节点的父级

  4. 返回保持原有结构的新树

优化方案一:性能提升版

const filterTree = (keyword = '', treeData = []) => {
  if (!treeData.length) return [];
  
  return treeData.reduce((result, node) => {
    // 检查当前节点是否匹配
    const isMatch = node.title1.includes(keyword);
    
    // 递归处理子节点
    const children = filterTree(keyword, node.children || []);
    
    // 如果当前节点匹配或有匹配的子节点,则保留该节点
    if (isMatch || children.length) {
      result.push({
        ...node,
        children: children.length ? children : undefined
      });
    }
    
    return result;
  }, []);
};

优化点:

  1. 使用reduce替代forEach,减少中间变量

  2. 简化条件判断逻辑

  3. 使用includes替代indexOf,语义更清晰

  4. 空子节点设为undefined而非空数组,减少内存占用

优化方案二:支持多字段搜索

const filterTreeAdvanced = (
  keyword = '', 
  treeData = [],
  searchFields = ['title1', 'title2', 'code']
) => {
  return treeData.filter(node => {
    // 检查当前节点是否匹配任意搜索字段
    const isNodeMatch = searchFields.some(
      field => node[field]?.toString().includes(keyword)
    );
    
    // 递归处理子节点
    const matchedChildren = filterTreeAdvanced(
      keyword, 
      node.children || [], 
      searchFields
    );
    
    // 保留当前节点条件
    return isNodeMatch || matchedChildren.length;
  }).map(node => ({
    ...node,
    children: filterTreeAdvanced(keyword, node.children || [], searchFields)
  }));
};

增强功能:

  1. 支持多个字段的搜索

  2. 自动处理字段值为非字符串的情况

  3. 更简洁的函数式编程风格

优化方案三:非递归实现(避免栈溢出)

const filterTreeIterative = (keyword, treeData) => {
  const stack = [...treeData.map(node => ({ node, parent: null }))];
  const result = [];
  
  while (stack.length) {
    const { node, parent } = stack.pop();
    
    const isMatch = node.title1.includes(keyword);
    let shouldKeep = isMatch;
    
    // 处理子节点
    const children = (node.children || []).map(child => ({
      node: child,
      parent: node
    }));
    
    // 如果有匹配的子节点,当前节点也需要保留
    const hasMatchingChildren = children.some(
      ({ node: child }) => child.title1.includes(keyword)
    );
    shouldKeep = shouldKeep || hasMatchingChildren;
    
    if (shouldKeep) {
      const newNode = { ...node, children: [] };
      if (parent) {
        parent.children.push(newNode);
      } else {
        result.push(newNode);
      }
    }
    
    // 将子节点压入栈中
    stack.push(...children);
  }
  
  return result;
};

优势:

  1. 使用迭代替代递归,避免栈溢出风险

  2. 显式处理父子关系,逻辑更清晰

  3. 适合处理深度很大的树结构

性能对比

方案优点缺点适用场景
基础递归实现简单性能一般,可能栈溢出小规模数据
优化递归代码简洁仍存在递归风险中等规模数据
多字段搜索功能强大性能开销稍大需要多字段搜索
迭代实现无栈溢出风险代码较复杂超深树结构

最佳实践建议

  1. 数据规模考虑

    • <1000节点:递归方案即可

    • 1000节点:考虑迭代实现

  2. 搜索体验优化

    • 添加防抖处理(300ms)

    • 支持模糊搜索(考虑正则表达式)

    • 高亮显示匹配内容

总结

树形数据的过滤搜索是一个常见但具有挑战性的需求。本文从基础实现出发,逐步介绍了多种优化方案,每种方案都有其适用场景。在实际项目中,建议:

  1. 根据数据规模选择合适算法

  2. 考虑添加缓存机制优化重复搜索

  3. 做好错误处理和性能监控

  4. 在用户体验和性能之间取得平衡

希望这些方案能为你的树形数据搜索需求提供有价值的参考!

评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值