数组的数据筛选

现有一组数据,其通过 parent_id 连接,有从属关系

[
    {
        id: 1,
        parent_id: 0
    },
    {
        id: 11,
        parent_id: 1    
    },
    {
        id: 12,
        parent_id: 1
    },
    {
        id: 111,
        parent_id: 11
    }
    {
        id: 21,
        parent_id: 2
    },
    {
        id: 22,
        parent_id: 2
    }
]

想要实现的效果是,指定一个 id ,从该数组中筛选出不包含id 及其有从属关系的数据。例如:指定 id 为 1,所有与 id 为 1 有关系的数据都会去除,输出的数据是

[
    {
        id: 21,
        parent_id: 2
    },
    {
        id: 22,
        parent_id: 2
    }
]
阅读 4.5k
9 个回答
let arr = [
  {
    id: 1,
    parent_id: 0
  },
  {
    id: 11,
    parent_id: 1
  },
  {
    id: 12,
    parent_id: 1
  },
  {
    id: 111,
    parent_id: 11
  },
  {
    id: 21,
    parent_id: 2
  },
  {
    id: 22,
    parent_id: 2
  }
]
const filterArr = (arr, id) => (arr.filter(val => val.parent_id === id).forEach(val => {arr = filterArr(arr, val.id)}), arr.filter(val => val.parent_id !== id && val.id !== id))
console.log(filterArr(arr, 1))

题主的问题已经解决了。

不过还是想发出自己的实现,昨天看到问题,一直关注这个问题,因为这个问题跟自己的项目中遇到的情况是一致的。
在定义数据的时候,后端给到的数据是一个扁平的,但是自己在处理这些数据的时候需要渲染成嵌套列表。
在项目中实现转换为树的思路,顺道对这个问题做了实现,算是总结一下这个过程。
依据自己的实现以及思路如下:

  1. 数组(将扁平的数据集,关系建立依赖节点数据) --> 树结构(建立关系不在依赖节点数据) // 这一步的好处在于 处理节点关系节点非常容易,而我的项目中的业务严重依赖节点关系,所以转换为树。

    • 对应 transformTree 方法, 其中需要注意的是,增加了不存在于数据集中的数据,也就是说,树中的节点不完全对应数据集中的数据。
  2. 树结构通过给定id找到树中的节点

    • 对应 findNodeByIdFromTree 方法
  3. 从树中寻找与当前树节点上有关的上下节点

    • 对应 findRelateNodesByIdFromTree 方法
    • 向叶子节点方向寻找

      • 通过 tree2nodes 迭代实现
    • 向根节点方向寻找

      • 通过 findUpNodesById 实现

其中2,3的功能完全是因为本题需要,我的项目中不需要这样的功能。

var c = [
  {
    id: 1,
    parent_id: 0
  },
  {
    id: 11,
    parent_id: 1
  },
  {
    id: 12,
    parent_id: 1
  },
  {
    id: 111,
    parent_id: 11
  },
  {
    id: 21,
    parent_id: 2
  },
  {
    id: 22,
    parent_id: 2
  }
]



var tree = {id:0, children:[], parent_id: null, isExist: false}
transformTree() //转换为关系树
console.log(findRelateNodesByIdFromTree(1))


/**
 * 从构造的树关系中寻找节点
 * @param {node} node 起始节点
 * @param {Number} id  id
 * @returns {node | null} n 返回找到的节点,没找到返回null
 */
function findNodeByIdFromTree(node, id) {
  let n = null
  // console.log("find start", JSON.stringify(node), id)
  if (node.id === id) {
    n = node
  } else {
    node.children.some(function(item){
      n = findNodeByIdFromTree(item, id);
      if(n) return true
    })
  }
  // console.log("find end: ", JSON.stringify(n))
  return n
}

/** 遍历节点集,根据从属关系转换为树结构, 构建一个树数据结构
 * @description
 * @author 069810
 * @date 2018-09-28
 */
function transformTree() {
  // 从数据集对id排序后遍历,
  // 排序后,id越小的应该越靠近树根节点
  cloneNode(c).sort(function (a, b) { return a.id - b.id }).map(function (item) {
    //每个节点添加一个子节点集
    item.children = []
    item.isExist = true
    // console.log('find ==> ', item.id, item.parent_id)
    
    // 在树中找到当前节点的父节点
    let treePNode = findNodeByIdFromTree(tree, item.parent_id);

    if (treePNode) {

      // 将当前节点的副本添加到树中,不影响源数据集 
      treePNode.children.push(cloneNode(item));
    } else {
      // 在树中没找到父节点 增加一个辅助树节点
      let xnode = { id: item.parent_id, parent_id: 0, isExist: false, children: [item]}
      tree.children.push(xnode)
    }
  })
  console.log('tree', JSON.stringify(tree))
}


/**
 * @description 从树中找到跟某一个节点有从属关系的节点
 * @author 069810
 * @date 2018-09-27
 * @param {Number} id
 * @returns {Array<node>}关系集
 */
function findRelateNodesByIdFromTree(id) {

  let n = []
  let cNode = findNodeByIdFromTree(tree, id) //在树中找到当前节点
  
  if(cNode) {
    
    // 向下 和 当前节点处理
    n = [...n, ...tree2nodes(cNode)]
    // console.log('result down==>', JSON.stringify(n))
    // 向上
    n = [...n, ...findUpNodesById(cNode.parent_id)]

  }
  // console.log("result up&down==>", JSON.stringify(n));
  n = n.map(item => { delete item.isExist; return item })
  return n
}

/**
 * @description 克隆一个节点
 * @author 069810
 * @date 2018-09-27
 * @param {DataObject} node
 * @returns {DataObject} 返回节点的副本
 */
function cloneNode(node) {
  return JSON.parse(JSON.stringify(node))
}

/**
 * @description 将一个树节点及其子节点转换为一个节点数组
 * @author 069810
 * @date 2018-09-27
 * @param {node} treeNode
 * @returns {Array<node>} 节点集, 扁平结构,无树结构
 */
function tree2nodes (treeNode) {

  let n = [];
  
  // 处理当前节点,克隆一份,以免新的结果集的处理会影响树
  n.push(cloneNode(treeNode)); 
  
  // 处理子节点
  treeNode.children.forEach(
    item => {
      n = [...n, ...tree2nodes(item)]
    }
  )
  // 删除新节点中多余的树结构部分
  n = n.map(
    item => {
      delete item.children
      return item
    }
  )

  // console.log("down ==> ",JSON.stringify(n));
  // 过滤辅助节点, 并删除辅助属性
  n = n.filter(item => item.isExist)
  return n
}
/**
 * @description 通过树向上找所有上级节点
 * @author 069810
 * @date 2018-09-28
 * @param {Number} id
 * @returns {Arrray<node>} 包括当前id节点以及所有上级节点集合
 */
function findUpNodesById(id) {
  let n = []
  if(id === tree.id) { //遇到跟节点
    n = [cloneNode(tree), ...n]
  } else {
    let cNode = cloneNode(findNodeByIdFromTree(tree, id)) //当前节点副本添加进去
    n = [...n, cNode, ...findUpNodesById(cNode.parent_id)]
  }

  // 删除新节点中多余的树结构部分
  n = n.map(
    item => {
      delete item.children
      return item
    }
  )
  // console.log("up==> ",JSON.stringify(n))
  // 过滤辅助节点
  n = n.filter(item => item.isExist)
  return n
}

把实现留在这里,下次如果遇到类似的问题可以给其他同学参考。

function filterData(id) {
    let parent_id = [id];
    return data.filter((item) => {
        if(item.id === id) {
            return false;
        }else if(item.parent_id === id || parent_id.indexOf(item.parent_id) !== -1) {
            parent_id.push(item.id);
            return false;
        }
            return true;
        })
}

试试这样行不行

function arrFilter(arr,id){
    let newarr = arr.filter(function(item,index){
            return item.parent_id !== id
    })
    return newarr
}
arr.filter(function (i) {
  return i.id !== id && i.parent_id !== id
});

这样写呢?我这边调试时可以的

function myFilter (list,id){

   if (Array.isArray(id)){
      id.forEach(_id=>{
         list = myFilter(list,_id)
      })
      return list
   }
   
   var relation_id = []
   list = list.filter((val)=>{
       if (val.id==id) relation_id.indexOf(val.parent_id)<=-1&&relation_id.push(val.parent_id)
         if (id==val.parent_id) relation_id.indexOf(val.id)<=-1&&relation_id.push(val.id)
       return val.id!=id&&val.parent_id!=id
   })

   if (relation_id.length>0){
     return myFilter(list,relation_id)
   }
   return list
}

楼主是想去掉id,parentId,以及id相同parentId不同的数据?

还是含有id值数字的都要去掉?

        let data = [
    {
        id: 1,
        parent_id: 0
    },
    {
        id: 2,
        parent_id: 0
    },
    {
        id: 11,
        parent_id: 1    
    },
    {
        id: 12,
        parent_id: 1
    },
    {
        id: 111,
        parent_id: 11
    },
    {
        id: 21,
        parent_id: 2
    },
    {
        id: 22,
        parent_id: 2
    }
];
function filterArr(data, id) {
    let parent_id = data.filter(i => i.id === id); // id相同的parentId 
    let list = data.reduce((arr, v) => { 
        // 去掉id,parentId,以及id相同parentId不同的数据
        if (v.id !== id && v.parent_id !== id && parent_id.some(j => j.parent_id !== v.parent_id)) {
            arr.push(v);
        }
        return arr;
    }, []);
    return list;
}

写在前面

  • 这是在比谁的代码短么?

解决

  • 示例代码如下: 假设你这个数组变量是arry
let result = arry.filter(ele => ele.id !== 1 && ele.parent_id === 1);

原理

  1. 循环arry
  2. 返回满足条件的元素集合
  3. 这里的条件就是id不等于1,parent_id等于1

参考

思路迭代,可以改装成使用filter过滤

let all_data = [
  {
    id: 1,
    parent_id: 0
  },
  {
    id: 11,
    parent_id: 1
  },
  {
    id: 12,
    parent_id: 1
  },
  {
    id: 111,
    parent_id: 11
  },
  {
    id: 21,
    parent_id: 2
  },
  {
    id: 22,
    parent_id: 2
  }
];

let in_data = [];
let filterData=(id,data)=>{
  let f_in_data = [];
  let f_notin_data = [];

  for(let item of data) {
    if(id == item.id || id == item.parent_id){
      f_in_data.push(item);
    }else{
      f_notin_data.push(item);
    }
  };

  if(f_in_data.length > 0){
    in_data = in_data.concat(f_in_data);
    for(let item of f_in_data){
      filterData(item.id,f_notin_data);
    }
  }
}
filterData(1,all_data);
console.log(all_data);
console.log(in_data);
控制台打印:
[
  {
    "id": 1,
    "parent_id": 0
  },
  {
    "id": 11,
    "parent_id": 1
  },
  {
    "id": 12,
    "parent_id": 1
  },
  {
    "id": 111,
    "parent_id": 11
  }
]

图片描述

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题