Применить фильтр к многомерному массиву и вернуть отфильтрованные данные вместе с родителем - PullRequest
0 голосов
/ 05 февраля 2019

У меня есть многомерный массив, как указано во фрагменте кода, я хочу отфильтровать этот массив по значению самого внутреннего массива, а затем вернуть это значение вместе с родительским.Например,

С

const nodes = [
    {
        value: 'Documents',
        label: 'Documents',
        children: [
            {
                value: 'Employee Evaluations.zip',
                label: 'Employee Evaluations.zip',
            },
            {
                value: 'Expense Report.pdf',
                label: 'Expense Report.pdf',
            },
            {
                value: 'notes.txt',
                label: 'notes.txt',
            },
        ],
    },
    {
        value: 'Photos',
        label: 'Photos',
        children: [
            {
                value: 'nyan-cat.gif',
                label: 'nyan-cat.gif',
            },
            {
                value: 'SpaceX Falcon9 liftoff.jpg',
                label: 'SpaceX Falcon9 liftoff.jpg',

            },
        ],
    },
]; 

Если я отфильтрую по «notes.txt», это должно дать

 [
    {
        value: 'Documents',
        label: 'Documents',
        children: [

            {
                value: 'notes.txt',
                label: 'notes.txt',
            }
        ]
]

Это то, что я пытался, но он просто возвращает самое внутреннеефильтрованное содержимое

const nodes = [
    {
        value: 'Documents',
        label: 'Documents',
        children: [
            {
                value: 'Employee Evaluations.zip',
                label: 'Employee Evaluations.zip',
            },
            {
                value: 'Expense Report.pdf',
                label: 'Expense Report.pdf',
            },
            {
                value: 'notes.txt',
                label: 'notes.txt',
            },
        ],
    },
    {
        value: 'Photos',
        label: 'Photos',
        children: [
            {
                value: 'nyan-cat.gif',
                label: 'nyan-cat.gif',
            },
            {
                value: 'SpaceX Falcon9 liftoff.jpg',
                label: 'SpaceX Falcon9 liftoff.jpg',
               
            },
        ],
    },
];
let key="notes.txt";
//let filtered=nodes.filter(n=>n.value===key);
let cfiltered=nodes.map(n=>n.children.filter(n1=>n1.value===key));
//console.log(filtered);
console.log(cfiltered);

Ответы [ 3 ]

0 голосов
/ 05 февраля 2019

Сначала map по всем parent и отфильтруйте несоответствующих потомков, затем отфильтруйте промежуточный результат по размеру children.

const nodes = [{
    value: 'Documents',
    label: 'Documents',
    children: [{
        value: 'Employee Evaluations.zip',
        label: 'Employee Evaluations.zip',
      },
      {
        value: 'Expense Report.pdf',
        label: 'Expense Report.pdf',
      },
      {
        value: 'notes.txt',
        label: 'notes.txt',
      },
    ],
  },
  {
    value: 'Photos',
    label: 'Photos',
    children: [{
        value: 'nyan-cat.gif',
        label: 'nyan-cat.gif',
      },
      {
        value: 'SpaceX Falcon9 liftoff.jpg',
        label: 'SpaceX Falcon9 liftoff.jpg',

      },
    ],
  },
];
let key="notes.txt";
const result = nodes.map(node => ({ ...node,
  children: node.children.filter(child => child.value === key)
})).filter(node => node.children.length);
console.log(result);

Надеюсь, это поможет!

0 голосов
/ 05 февраля 2019

Я подозреваю, что вы, вероятно, могли бы иметь более высокие измерения, чем два.Вы хотите рассматривать это как проблему дерева.Поскольку вы заботитесь о родителе и ребенке, вы можете использовать поиск в глубину.

function getNodeWithChild( accumulator, rootNode, searchValue ) {
  if (!rootNode || !rootNode.children) return accumulator;

  let parentNode;
  rootNode.children.forEach( child => {
     accumulator = getNodeWithChild(accumulator, child, searchValue);
     if (child.value === searchValue || child.label === searchValue) {
       if (parentNode) {
          parentNode.children.push(child);
       } else {
         parentNode = Object.assign({}, rootNode);
         parentNode.children = [child];
       }
    }
    if (parentNode) {
      accumulator.push(parentNode);
    }
  }
  return accumulator
} 

// And you call it like this:
const tree = { children: nodes } // just to simplify treat it like the same node as the rest
const filteredNodes = getNodeWithChild( [], rootNode, 'notes.txt'); 

Это рекурсивная версия, но ее можно сделать итеративной с помощью очереди.Это не проверено, возможно, можно использовать некоторые отладки.Но он должен возвращать parentNode каждого дочернего элемента со значением.Если и родитель, и потомок содержат значение, оно будет возвращать обе стороны рядом.Это удалит всех потомков, которые также не имеют значения.

0 голосов
/ 05 февраля 2019

Чисто на макушке головы не проверялось, но идея была бы:

  • фильтровать узлы хотя бы с одним child.value == ключом
  • фильтровать потомковкаждый результирующий узел:

Это будет выглядеть так:

nodes.filter(n => n.children.reduce((cur, acc) => acc || cur.value == key, false).length > 0)
     .map(n => Object.assign(n, { children: n.children.filter(c => c.value == key }))

Может быть?

[Правка] добавил начальное значение для уменьшения

[Правка] добавил Object.assign, чтобы вы также получили оригинальный объект.Я действительно должен сначала проверить это;), но вы получаете jist!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...