【问题标题】:Struggling with recursion - function return an empty array when filtering an array of objects递归中苦苦挣扎-过滤对象数组时函数返回一个空数组
【发布时间】:2021-06-29 14:15:30
【问题描述】:

我有以下递归函数:

const findChildren = (id, array) => {
   const matchingItems = array.filter(arrayItem => {
       if (arrayItem.children) {
          findChildren(id, arrayItem.children)
       }
   
       return arrayItem.item.parent === id;
   })
     
   return matchingItems;
}

我试图只查找具有相同parent 属性的元素,该属性等于我作为参数传入函数的id。这是我正在使用的对象数组:

const data = [
  {
    "item": {
      "id": 0,
      "name": "aaa"
    },
    "children": [
      {
        "item": {
          "id": 1,
          "name": "bbb",
          "parent": 0
        }
      },
      {
        "item": {
          "id": 2,
          "name": "ccc",
          "parent": 0
        }
      }
    ]
  },
  {
    "item": {
      "id": 3,
      "name": "ddd"
    },
    "children": [
      {
        "item": {
          "id": 4,
          "name": "eee",
          "parent": 3
        }
      },
      {
        "item": {
          "id": 5,
          "name": "fff",
          "parent": 3
        },
        "children": [
          {
            "item": {
              "id": 6,
              "name": "ggg",
              "parent": 5
            }
          }
        ]
      }
    ]
  },
  {
    "item": {
      "id": 7,
      "name": "hhh"
    },
    "children": [
      {
        "item": {
          "id": 8,
          "name": "iii",
          "parent": 7
        },
        "children": [
          {
            "item": {
              "id": 9,
              "name": "jjj",
              "parent": 8
            },
            "children": [
              {
                "item": {
                  "id": 10,
                  "name": "kkk",
                  "parent": 9
                }
              },
              {
                "item": {
                  "id": 11,
                  "name": "lll",
                  "parent": 9
                }
              },
              {
                "item": {
                  "id": 12,
                  "name": "mmm",
                  "parent": 9
                }
              }
            ]
          },
          {
            "item": {
              "id": 13,
              "name": "nnn",
              "parent": 8
            },
            "children": [
              {
                "item": {
                  "id": 14,
                  "name": "ooo",
                  "parent": 13
                }
              },
              {
                "item": {
                  "id": 15,
                  "name": "ppp",
                  "parent": 13
                }
              },
              {
                "item": {
                  "id": 16,
                  "name": "qqq",
                  "parent": 13
                }
              }
            ]
          }
        ]
      }
    ]
  },
  {
    "item": {
      "id": 17,
      "name": "rrr"
    },
    "children": [
      {
        "item": {
          "id": 18,
          "name": "sss",
          "parent": 17
        }
      },
      {
        "item": {
          "id": 19,
          "name": "ttt",
          "parent": 17
        },
        "children": [
          {
            "item": {
              "id": 20,
              "name": "uuu",
              "parent": 19
            }
          },
          {
            "item": {
              "id": 21,
              "name": "vvv",
              "parent": 19
            }
          }
        ]
      },
      {
        "item": {
          "id": 22,
          "name": "www",
          "parent": 17
        }
      },
      {
        "item": {
          "id": 23,
          "name": "xxx",
          "parent": 17
        },
        "children": [
          {
            "item": {
              "id": 24,
              "name": "yyy",
              "parent": 23
            }
          },
          {
            "item": {
              "id": 25,
              "name": "zzz",
              "parent": 23
            }
          }
        ]
      }
    ]
  }
]

当像这样调用函数时,我得到undefined

console.log(findChildren(3, data));

我尝试使用mapfind,结果总是undefined。我的想法用完了,并且真的在递归中挣扎。任何帮助,将不胜感激。谢谢。

【问题讨论】:

    标签: javascript arrays object recursion


    【解决方案1】:

    处理递归的方法有很多种,我只用了一种方法,

    您遇到的问题是您没有在任何地方添加子结果,您只是在过滤它。

    在下面的示例中,我使用一个辅助对象来收集所有子结果

    const data = [{
        "item": {
          "id": 0,
          "name": "aaa"
        },
        "children": [{
            "item": {
              "id": 1,
              "name": "bbb",
              "parent": 0
            }
          },
          {
            "item": {
              "id": 2,
              "name": "ccc",
              "parent": 0
            }
          }
        ]
      },
      {
        "item": {
          "id": 3,
          "name": "ddd"
        },
        "children": [{
            "item": {
              "id": 4,
              "name": "eee",
              "parent": 3
            }
          },
          {
            "item": {
              "id": 5,
              "name": "fff",
              "parent": 3
            },
            "children": [{
              "item": {
                "id": 6,
                "name": "ggg",
                "parent": 5
              }
            }]
          }
        ]
      },
      {
        "item": {
          "id": 7,
          "name": "hhh"
        },
        "children": [{
          "item": {
            "id": 8,
            "name": "iii",
            "parent": 7
          },
          "children": [{
              "item": {
                "id": 9,
                "name": "jjj",
                "parent": 8
              },
              "children": [{
                  "item": {
                    "id": 10,
                    "name": "kkk",
                    "parent": 9
                  }
                },
                {
                  "item": {
                    "id": 11,
                    "name": "lll",
                    "parent": 9
                  }
                },
                {
                  "item": {
                    "id": 12,
                    "name": "mmm",
                    "parent": 9
                  }
                }
              ]
            },
            {
              "item": {
                "id": 13,
                "name": "nnn",
                "parent": 8
              },
              "children": [{
                  "item": {
                    "id": 14,
                    "name": "ooo",
                    "parent": 13
                  }
                },
                {
                  "item": {
                    "id": 15,
                    "name": "ppp",
                    "parent": 13
                  }
                },
                {
                  "item": {
                    "id": 16,
                    "name": "qqq",
                    "parent": 13
                  }
                }
              ]
            }
          ]
        }]
      },
      {
        "item": {
          "id": 17,
          "name": "rrr"
        },
        "children": [{
            "item": {
              "id": 18,
              "name": "sss",
              "parent": 17
            }
          },
          {
            "item": {
              "id": 19,
              "name": "ttt",
              "parent": 17
            },
            "children": [{
                "item": {
                  "id": 20,
                  "name": "uuu",
                  "parent": 19
                }
              },
              {
                "item": {
                  "id": 21,
                  "name": "vvv",
                  "parent": 19
                }
              }
            ]
          },
          {
            "item": {
              "id": 22,
              "name": "www",
              "parent": 17
            }
          },
          {
            "item": {
              "id": 23,
              "name": "xxx",
              "parent": 17
            },
            "children": [{
                "item": {
                  "id": 24,
                  "name": "yyy",
                  "parent": 23
                }
              },
              {
                "item": {
                  "id": 25,
                  "name": "zzz",
                  "parent": 23
                }
              }
            ]
          }
        ]
      }
    ]
    
    const findChildren = (id, array) => {
      var matchingItems = [];
      const currentItems = array.filter(arrayItem => {
    
        if (arrayItem.children) {
          const childrenItems = findChildren(id, arrayItem.children);
          if (childrenItems.length > 0) {
            matchingItems.push(...childrenItems);
          }
    
        }
    
        return arrayItem.item.parent === id;
    
      })
    
      if (currentItems.length > 0) {
        matchingItems.push(currentItems);
      }
      return matchingItems;
    }
    
    console.log(findChildren(3, data));

    【讨论】:

    • 谢谢,现在很有意义,因为我确实没有在任何地方添加结果。
    【解决方案2】:

    我将在一个可重用函数之上构建它,该函数遍历您的children-branched 对象,收集与谓词匹配的对象。它可能看起来像这样:

    const collect = (pred) => (xs = []) => 
      xs .flatMap (x => [
        ... (pred (x) ? [x] : []),
        ... collect (pred) (x .children)
      ])
    
    const findChildren = (id, data) => 
      collect (({item: {parent}}) => parent == id) (data)
    
    const data = [{item: {id: 0, name: "aaa"}, children: [{item: {id: 1, name: "bbb", parent: 0}}, {item: {id: 2, name: "ccc", parent: 0}}]}, {item: {id: 3, name: "ddd"}, children: [{item: {id: 4, name: "eee", parent: 3}}, {item: {id: 5, name: "fff", parent: 3}, children: [{item: {id: 6, name: "ggg", parent: 5}}]}]}, {item: {id: 7, name: "hhh"}, children: [{item: {id: 8, name: "iii", parent: 7}, children: [{item: {id: 9, name: "jjj", parent: 8}, children: [{item: {id: 10, name: "kkk", parent: 9}}, {item: {id: 11, name: "lll", parent: 9}}, {item: {id: 12, name: "mmm", parent: 9}}]}, {item: {id: 13, name: "nnn", parent: 8}, children: [{item: {id: 14, name: "ooo", parent: 13}}, {item: {id: 15, name: "ppp", parent: 13}}, {item: {id: 16, name: "qqq", parent: 13}}]}]}]}, {item: {id: 17, name: "rrr"}, children: [{item: {id: 18, name: "sss", parent: 17}}, {item: {id: 19, name: "ttt", parent: 17}, children: [{item: {id: 20, name: "uuu", parent: 19}}, {item: {id: 21, name: "vvv", parent: 19}}]}, {item: {id: 22, name: "www", parent: 17}}, {item: {id: 23, name: "xxx", parent: 17}, children: [{item: {id: 24, name: "yyy", parent: 23}}, {item: {id: 25, name: "zzz", parent: 23}}]}]}]
    
    console .log (findChildren (3, data))
    .as-console-wrapper {max-height: 100% !important; top: 0}

    collect 接受任意谓词并返回一个函数。该函数接受具有递归嵌套children 数组的对象数组,并返回与谓词匹配的所有元素。

    然后findChildren传递collect一个简单的谓词测试你的父id条件,并将对象列表传递给生成的函数。

    我更喜欢这种轻微的变体:

    const findChildren = (id) => 
      collect (({item: {parent}}) => parent == id)
    
    findChildren (3) (data)
    

    这允许您存储部分应用的函数findChildren (3) 以用于多个对象。虽然这对于您的情况可能不是必需的,但它增加了很好的灵活性。

    【讨论】:

      【解决方案3】:

      这是一个使用object-scan的迭代解决方案

      // const objectScan = require('object-scan');
      
      const data = [{ item: { id: 0, name: 'aaa' }, children: [{ item: { id: 1, name: 'bbb', parent: 0 } }, { item: { id: 2, name: 'ccc', parent: 0 } }] }, { item: { id: 3, name: 'ddd' }, children: [{ item: { id: 4, name: 'eee', parent: 3 } }, { item: { id: 5, name: 'fff', parent: 3 }, children: [{ item: { id: 6, name: 'ggg', parent: 5 } }] }] }, { item: { id: 7, name: 'hhh' }, children: [{ item: { id: 8, name: 'iii', parent: 7 }, children: [{ item: { id: 9, name: 'jjj', parent: 8 }, children: [{ item: { id: 10, name: 'kkk', parent: 9 } }, { item: { id: 11, name: 'lll', parent: 9 } }, { item: { id: 12, name: 'mmm', parent: 9 } }] }, { item: { id: 13, name: 'nnn', parent: 8 }, children: [{ item: { id: 14, name: 'ooo', parent: 13 } }, { item: { id: 15, name: 'ppp', parent: 13 } }, { item: { id: 16, name: 'qqq', parent: 13 } }] }] }] }, { item: { id: 17, name: 'rrr' }, children: [{ item: { id: 18, name: 'sss', parent: 17 } }, { item: { id: 19, name: 'ttt', parent: 17 }, children: [{ item: { id: 20, name: 'uuu', parent: 19 } }, { item: { id: 21, name: 'vvv', parent: 19 } }] }, { item: { id: 22, name: 'www', parent: 17 } }, { item: { id: 23, name: 'xxx', parent: 17 }, children: [{ item: { id: 24, name: 'yyy', parent: 23 } }, { item: { id: 25, name: 'zzz', parent: 23 } }] }] }];
      
      const find = objectScan(['**(^children$).item.parent'], {
        useArraySelector: false,
        rtn: 'gparent',
        reverse: false,
        filterFn: ({ value, context }) => value === context
      });
      
      console.log(find(data, 3));
      // => [ { item: { id: 4, name: 'eee', parent: 3 } }, { item: { id: 5, name: 'fff', parent: 3 }, children: [ { item: { id: 6, name: 'ggg', parent: 5 } } ] } ]
      .as-console-wrapper {max-height: 100% !important; top: 0}
      <script src="https://bundle.run/object-scan@15.0.0"></script>

      免责声明:我是object-scan的作者

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-03-15
        • 1970-01-01
        • 1970-01-01
        • 2017-09-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-12
        相关资源
        最近更新 更多