简体   繁体   English

满足特定条件时停止递归方法

[英]Stop a recursive method when a certain condition is met

I have a class called Item , and it's defined as following : 我有一个叫做Item的类,它的定义如下:

public class Item {
  private Long id;
  private String text;
}

And it's DTO is as following : DTO如下:

public class ItemDTO {
  private String id;
  private String text;
  private List<ItemDTO> children;
}

So using a DAO function I will retrieve an object children using it's id from database, as following : 因此,使用DAO函数,我将从数据库中使用其id检索对象的子对象,如下所示:

List<Item> children = itemDAO.findChildrenForItem(id);

And for each child I will retrieve it's children and so on..., for that I created a recursive function, which worked in this case : 对于每个孩子,我将检索它的孩子,依此类推...,为此,我创建了一个递归函数,在这种情况下该函数起作用:

public List<ItemDTO> process(Long id) {
    List<ItemDTO> list = new ArrayList<>();

    // Get children
    List<Item> children = itemDAO.findChildrenForItem(id);

    if (children != null && children.size() > 0) {
      for (Item child : children) {
        ItemDTO dto = new ItemDTO();
        dto.setId(String.valueOf(child.getId()));
        dto.setText(child.getLib());
        dto.setChildren(process(child.getId()));
        list.add(dto);
      }
    }

    return list;
  }

Here what I want to do is that when I reach the 5th iteration in the recursive method to stop and move to the next element in the children array. 我想做的是,当我在递归方法中达到第5次迭代时,停止并移至children数组中的下一个元素。

So the first level children will have 4 level children, and the second level children will have 3 level children and so on..., so this is what I tried : 因此,第一级儿童将有4级儿童,第二级儿童将有3级儿童,依此类推...,所以这是我尝试的方法:

public List<ItemDTO> process(Long id, Integer level) {
    List<ItemDTO> list = new ArrayList<>();

    // Get children
    List<Item> children = itemDAO.findChildrenForItem(id);

    if (children != null && children.size() > 0) {
      for (Item child : children) {
        level = level != null ? level : 0;
        ItemDTO dto = new ItemDTO();
        dto.setId(String.valueOf(child.getId()));
        dto.setText(child.getLib());
        level++;
        dto.setChildren(level <= 4 ? process(child.getId(), level) : null);
        list.add(dto);
        level = 0;
      }
    }

    return list;
  }

But this didn't work I always get children more than the forth level. 但这没有用,我得到的孩子总是比四级还多。

How can I solve this ? 我该如何解决?

You're never checking the value of level to see if it's reached your goal. 您永远不会检查 level的值来查看它是否达到您的目标。 You also seem to be overcomplicating the use of that level variable. 您似乎也使该level变量的使用过于复杂。 Consider a structure like this: 考虑这样的结构:

public List<ItemDTO> process(Long id, Integer level) {
    List<ItemDTO> list = new ArrayList<>();

    // check the recursive logic's terminating condition
    if (level == 5) {
        // reached the intended bottom, return
        return list;
    }

    List<Item> children = itemDAO.findChildrenForItem(id);
    if (children != null && children.size() > 0) {
        for (Item child : children) {
            level = level != null ? level : 0;
            ItemDTO dto = new ItemDTO();
            dto.setId(String.valueOf(child.getId()));
            dto.setText(child.getLib());

            // you don't need a lot of logic here, just increment the level in the recursive call
            dto.setChildren(process(child.getId(), level + 1));

            list.add(dto);
        }
    }

    return list;
}

So when the target "level" is reached, the method doesn't bother finding the children and simply returns an empty list. 因此,当达到目标“级别”时,该方法不会费心查找子级,而只是返回一个空列表。 (Or you can return null , or something else, that's up to you.) Then in the recursion to the next "level" all you need to do is add 1 to the current "level". (或者您可以返回null或其他方式,完全由您决定。)然后在递归到下一个“级别”时,您需要做的就是将1添加到当前的“级别”。

Essentially it looks like you were trying to have a single global variable which knows the full state of the recursion, and base logic off of that. 从本质上讲,您似乎正在尝试拥有一个唯一的全局变量,该变量知道递归的完整状态,并以此为基础进行逻辑运算。 Instead, have the recursive method itself simply know when to stop based on the value that's passed to it. 相反,让递归方法本身仅根据传递给它的值知道何时停止。 And just pass the modified value each time. 并且每次都传递修改后的值。

In general, the first task of a recursive method should be to stop the recursion and return to the caller. 通常,递归方法的第一个任务应该是停止递归并返回给调用者。 Then, do the work for the current step in the recursive call stack if you are not returning immediately. 然后,如果您不立即返回,则对递归调用堆栈中的当前步骤进行操作。

That said, you could also let the database do this for you with a hierarchical query. 也就是说,您还可以通过分层查询让数据库为您完成此任务。 This would bring all your data back in one resultset and eliminate the need for multiple calls to the db. 这会将所有数据带回到一个结果集中,并且无需多次调用数据库。

Something along the lines of this for Oracle: 对于Oracle,与此类似:

select id, text, LEVEL
from items
where LEVEL < 5
start with id = ?
connect by prior parent_id = id
order siblings by ...

For MySQL, there is a similar option. 对于MySQL,有一个类似的选项。 See this for example - How to create a MySQL hierarchical recursive query 参见示例- 如何创建MySQL分层递归查询

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM