Saya perlu memfilter struktur bersarang, yang terlihat seperti ini, berdasarkan kueri. Saya perlu mengembalikan semua objek, termasuk objek induk dari subpohon, yang cocok dengan string kueri dalam nama objek. Mohon bantuannya, saya buntu.

[
   {
     name: 'bob',
     type: 1,
     children: [
       {
         name: 'bob',
         type: 2,
         children: [
           {
             name: 'mike',
             type: 3,
             children: [ 
               {
                 name:'bob',
                 type: 7,
                 children: []
               },
               {
                 name: 'mike',
                 type: 9,
                 children: []
               }
             ]
           }
         ]
       },
       {
         name: 'mike',
         type: 2
       }
     ]
   }
 ]

Saat ini saya dapat menemukan kecocokan di pohon secara rekursif, tetapi fungsinya mengembalikan objek pada kecocokan pertama dan tidak mencari lebih dalam pada sub level di objek yang sama. Adakah saran, bagaimana saya bisa memodifikasi kode untuk menelusuri semua level secara rekursif?

  return tree.map(copy).filter(function filterNested(node) {
    if (node.name.toLowerCase().indexOf(query) !== -1) {
      return true;
    }

    if (node.children) {
      return (node.children = node.children.map(copy).filter(filterNested))
        .length;
    }
  });

Jika saya mencari kueri 'bob', hasil yang diharapkan adalah,

 const arr = [
   {
     name: 'bob',
     type: 1,
     children: [
       {
         name: 'bob',
         type: 2,
         children: [
           {
             name: 'mike',
             type: 3,
             children: [ 
               {
                 name:'bob',
                 type: 7
               },
  
             ]
           }
         ]
       },
     ]
   }
 ]

6
leonard0 29 Oktober 2019, 23:51

6 jawaban

Jawaban Terbaik

Anda bisa mengurangi array dan membangun objek baru dengan anak-anak opsional, jika panjangnya tidak nol.

function filter(array, fn) {
    return array.reduce((r, o) => {
        var children = filter(o.children || [], fn);
        if (fn(o) || children.length) r.push(Object.assign({}, o, children.length && { children }));
        return r;
    }, []);
}

var data = [{ name: 'bob', type: 1, children: [{ name: 'bob', type: 2, children: [{ name: 'mike', type: 3, children: [{ name: 'bob', type: 7 }, { name: 'same', typ: 9 }] }] }, { name: 'mike', type: 2 }] }],
    result = filter(data, ({ name }) => name.toLowerCase() === 'bob');

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
3
Nina Scholz 29 Oktober 2019, 21:52

Saya hanya akan menggunakan pola pengunjung lama yang baik untuk melintasi dan membangun pohon baru.

class Visitor {
    constructor(predicate) {
        this.predicate = predicate;
    }

    visit(item) {
        if (Array.isArray(item)) {
            return this.visitArray(item);
        } else if (item) {
            return this.visitItem(item);
        }
    }

    visitArray(item) {
        const result = [];
        for (let e of item) {
            const item = this.visit(e);
            if (item) {
                result.push(item);
            }
        }
        return result;
    }

    visitItem(item) {
        const children = this.visit(item.children);
        const hasChildren = (children && children.length > 0);

        if (hasChildren || this.predicate(item)) {
            return {
                name: item.name,
                type: item.type,
                children: children
            }
        }
        return null;
    }
}


const visitor = new Visitor((item) => item.name === "bob");
const result = visitor.visit(data);

console.log(result);
1
Edin Omeragic 29 Oktober 2019, 21:35

Anda dapat menggunakan pengurangan rekursif untuk ini, di mana Anda memeriksa apakah ada anak-anak atau apakah namanya cocok sebelum Anda mengakumulasi objek:

const example = [{
  name: 'bob',
  type: 1,
  children: [{
      name: 'bob',
      type: 2,
      children: [{
        name: 'mike',
        type: 3,
        children: [{
            name: 'bob',
            type: 7,
            children: []
          },
          {
            name: 'mike',
            type: 9,
            children: []
          }
        ]
      }]
    },
    {
      name: 'mike',
      type: 2
    }
  ]
}];

function reduceName(accum, item, matcher) {
  item.children = (item.children || []).reduce((a,i)=>reduceName(a,i,matcher),[]);
  if (!item.children.length) delete item.children;
  if (matcher(item) || item.children) accum.push(item);
  return accum;
}

console.log(example.reduce((a,i)=>reduceName(a,i,x=>x.name==='bob'),[]));
1
Ruzihm 29 Oktober 2019, 21:18

Sesuatu seperti ini, mungkin?

function nestedFilter(query, nodes) {
  return nodes.reduce((result, node) => {
    const filteredChildren = node.children && nestedFilter(query, node.children);
    const nameMatches = node.name.toLowerCase().indexOf(query) !== -1;
    const childrenMatch = filteredChildren && filteredChildren.length;
    const shouldKeep = nameMatches || childrenMatch;
    return shouldKeep 
      ? result.concat({ ...node, children: filteredChildren }) 
      : result;    
  }, []);
}
1
Jacob 29 Oktober 2019, 21:10

Saya pikir pertanyaan ini akan selalu relevan jadi inilah cara saya melakukannya! Setelah beberapa jam ;)

var res = yourArray.filter(function f(el) {
    if (el.children.length > 0) {
        el.children = el.childreb.filter(f);
    }
    if (el.name === "bob") return true; // you can put the condition you need here.
})
//res is your returned array

Benar-benar berharap kode ini akan bermanfaat bagi sebagian dari Anda :)

0
Nathan Adda 8 Juni 2020, 05:59

Saat yang tepat untuk mempelajari rekursi bersama dan gaya passing lanjutan

const data =
  [{name:'bob',type:1,children:[{name:'bob',type:2,children:[{name:'mike',type:3,children:[ {name:'bob',type:7,children:[]},{name:'mike',type:9,children:[]}]}]},{name:'mike',type:2}]}]

const identity = x => x

const search = (all = [], query = identity, pass = identity) =>
  all.flatMap(v => search1(v, query, pass))

const search1 = (one = {}, query = identity, pass = identity) =>
  query(one)
    ? pass([ { ...one, children: search(one.children, query) } ])
    : search
        ( one.children
        , query
        , children =>
            children.length === 0
              ? pass([])
              : pass([ { ...one, children } ])
        )

const result =
  search(data, x => x.name === "bob")

console.log(JSON.stringify(result, null, 2))
1
Thank you 8 Juni 2020, 15:26