JavaScript: фильтрация между одним и тем же вложенным ключом с использованием lodash - PullRequest
1 голос
/ 03 июля 2019

У меня есть массив 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, где в againstTable?

не существует такого же exid?

Чтобы проиллюстрировать, мне нужен метод, который может получить следующий массив результатов из двух приведенных выше массивов:

 [
    {
    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;
}

1 Ответ

1 голос
/ 03 июля 2019

Этого можно достичь без lodash , используя сокращение встроенного массива .

Например, вы можете вызвать reduce в массиве baseTable, где для каждой итерации вы ищете элемент в againstTable, который соответствует exid.

Если совпадений не найдено, добавьте baseItem к вашему выходному массиву (это представляет собой случай, когда exid: "2" из ваших данных выше добавляется к результату).

Если совпадение найдено, изучите дочерние вложенные массивы baseItem и againstItem (если есть) и отфильтруйте элементы в массиве 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);
...