首页 > 解决方案 > JavaScript:使用 lodash 在相同的嵌套键之间进行过滤

问题描述

我有一个数组baseTable,它看起来像这样:

baseTable = [
    {
        exid: "2",
        name: "aa",
        children_meta: {
        has: false
        }
    },
    {
        exid: "1",
        name: "aa1",
        children_meta: {
        has: false
        }
    },
    {
        exid: "3",
        name: "bb",
        children_meta: {
        has: true
        },
        children: [
        {
            exid: "101",
            name: "c101"
        },
        {
            exid: "102",
            name: "c102"
        }
        ]
    }
]

和另一个这样的数组againstTable

againstTable = [
    {
        exid: "2",
        name: "aa",
        children_meta: {
        has: false
        }
    },
    {
        exid: "3",
        name: "bb",
        children_meta: {
        has: true
        },
        children: [
        {
            exid: "102",
            name: "c102"
        }
        ]
    }
]

是否有一种 lodash 方法可以从baseTable数组中选择exid不存在相同对象的对象againstTable

为了说明,我需要可以从上面的两个数组中产生以下数组结果的方法:

 [
    {
    exid: "1",
    name: "aa1",
    children_meta: {
        has: false
    }
    },
    {
        exid: "3",
        name: "bb",
        children_meta: {
        has: true
        },
        children: [
            {
                exid: "101",
                name: "c101"
            }
        ]
    }
]

这就是我尝试的方式,但这种方法对于一项小任务来说太大了:

conditionalRender(o: { baseTable; againstTable }) {
    const { baseTable, againstTable } = o;
    // Check if there are no duplicates in the base
    // table; check against, "against table"
    // This could be possible after user performs a search
    console.log(baseTable, "..base");
    console.log(againstTable, "...againsr");
    const baseMap = {};
    const againstMap = {};
    baseTable.forEach(row => (baseMap[row.pid] = row));
    againstTable.forEach(row => (againstMap[row.pid] = row));

    // const against_ids = new Set(againstTable.map(({ pid }) => pid));
    // return baseTable.filter(({ pid }) => !against_ids.has(pid));
    const filteredBaseTable: { [index: string]: any } = [];
    baseTable.forEach(({ pid }) => {
    if (baseMap[pid].children_meta.has) {
        // If it is a group, check if there exists
        // a part in another table
        if (againstMap[pid]) {
        // Opposite table also has the same eequipment group
        // Will keep the children that are not present in the
        // opposite table
        // Each child can be differentiated by its exid
        const exidsInAgainstTable = new Set(
            againstMap[pid].children.map(crow => crow.exid)
        );
        // Keep only those ids in base table that do not exist in against table
        const originalBaseChildren = baseMap[pid].children;
        baseMap[pid].children = originalBaseChildren.filter(
            ({ exid }) => !exidsInAgainstTable.has(exid)
        );
        filteredBaseTable.push(baseMap[pid]);
        }
    } else {
        if (!againstMap[pid]) {
        filteredBaseTable.push(baseMap[pid]);
        }
    }
    });
    return filteredBaseTable;
}

标签: javascriptlodash

解决方案


这可以在不lodash 使用内置数组缩减的情况下实现。

例如,您可以调用数组 where 对于每次迭代,您都在其中搜索reduce匹配on的项目。baseTableagainstTableexid

如果未找到匹配项,请将 添加baseItem到输出数组(这表示将上述数据中的exid:"2"添加到结果中的情况)。

如果找到匹配项,则检查baseItemagainstItem(如果存在)的子数组,并过滤baseItem.children​​数组中该子数组exid从未出现在againstItem.children子数组中的项。如果过滤后的结果不为空,则baseItem使用过滤后的结果更新 children 数组并将其添加到您的output.

表达这一点的一种方法是代码:

const baseTable=[{exid:"2",name:"aa",children_meta:{has:false}},{exid:"1",name:"aa1",children_meta:{has:false}},{exid:"3",name:"bb",children_meta:{has:true},children:[{exid:"101",name:"c101"},{exid:"102",name:"c102"}]}];const againstTable=[{exid:"2",name:"aa",children_meta:{has:false}},{exid:"3",name:"bb",children_meta:{has:true},children:[{exid:"102",name:"c102"}]}];

const result = baseTable.reduce((output, baseItem) => {

  const matchOnExid = againstTable.find(againstItem => { 
      return againstItem.exid === baseItem.exid; 
  });

  if (matchOnExid) {

    /* If match of exid found from agaistTable for current baseTable item
    then examine the children sub-arrays */
    const baseChildren = baseItem.children;
    const againstChildren = matchOnExid.children;

    if (Array.isArray(baseChildren) && Array.isArray(againstChildren)) {

      /* If valid children sub-arrays exist of items, filter a subset of the
      baseItem children for items that do not exist in the children sub-array
      of the matched againstItem */
      const matchChildrenOnExid = baseChildren.filter(baseChildItem => 
      {
          return againstChildren.every(againstChildItem => {
              return againstChildItem.exid !== baseChildItem.exid;
          });
      });

      if (matchChildrenOnExid.length > 0) {

        /* If a subset of children do exist, then baseItem can be added to
        resulting array. Note also that we need to update the children array
        of the returned result to reflect the subset that was just found */
        output.push({ ...baseItem,
          children: matchChildrenOnExid
        });
      }
    }
  } else {
    /* If no match of exid found, just add the baseItem to the
    result */
    output.push(baseItem);
  }

  return output;

}, []);

console.log(result);


推荐阅读