【问题标题】:Java For loop counter not working when calling recursive method调用递归方法时Java For循环计数器不起作用
【发布时间】:2014-03-10 13:45:03
【问题描述】:

我正在尝试遍历对象列表并将它们的属性打印到 xml 文件中,但是由于需要关闭标记,我需要递归遍历子对象并在返回顶部之前打印它们的属性堆栈的最高组件写出闭包标签。

然而,for 循环和递归似乎在 java 中不能很好地配合使用,因为一些奇怪的原因,当我在 for 循环内部有一个方法调用自身时,计数器“重置”(本质上,计数器变量似乎在尝试使用所有 3 个参数正常使用 for 循环时取消分配自身)在进入循环的下一次迭代时,导致无限循环。

我尝试了许多不同的方法,包括尝试在类构造函数中使计数器成为静态变量,并用 for-each 循环代替,所有这些都存在类似的问题。我最接近找到答案的是以下解决方案,将计数器传入并返回到递归方法中:

Adding counter to a loop inside a recursive method - Java

然而,虽然这适用于上面的情况,它只包含一个值,但它会导致问题,如果我不调整计数器,它现在比它需要的高一个,并导致 indexOutOfBound 异常,并且如果我在进入循环之前确实减去了计数器和/或将其分配给 0,则即使我在将计数器传回之前明确地将计数器加 1,也会返回 0。

这些都没有任何意义。这是我正在使用的代码的基本逻辑:如果有人知道这有什么问题,或者知道任何替代解决方案,请告诉我。

public int write(PrintWriter fromPortalTXTFile, String level, Integer counter){
    ...
    if (children) {
        for(;counter < childrenList.size();) {
            counter++;
            counter = ClassName.get(counter - 1).write(fromPortalTXTFile, level, counter);
        }
    }
    else {
        counter++;
    }

    return counter;
}

编辑:由于各种请求,这是整个方法代码。它包含对不同功能的引用,并且具有与我遇到的问题无关的逻辑,我无法详细说明该方法的每个部分如何工作。问题在于如果组件有子组件则输入的 for 循环,我仍然认为上面的说明更好。

// Writes the information about this BOM component out to the from_portal.txt file
public int write(PrintWriter fromPortalTXTFile, String level, Integer counter) throws Exception {

    //Retrieve the item and revision of the BOM line.  If
    //read access is denied, skip the BOM line.
    Debug.println("PERF: Inside printXMLTag: Reading BOMLine props start");        
    TCComponentItem item = TXDExportAction.getItem(currentComponent);
    TCComponentItemRevision rev = TXDExportAction.getItemRevision(currentComponent);
    //if (item == null || rev == null) {
    //    return null;
    //}
    String itemID = item.getProperty("item_id");
    String revID = rev.getProperty("item_revision_id");

    // Get the pdm_occ_id of the current component
    String pdmOccID = TXDExportAction.getBOMLineProperty(currentComponent, "bl_occurrence_uid");

    // Determine if the item is currently selected in the BOM window
    Boolean isSelected = false;

    //if (selectedComponents.contains(currentComponent)){
    //  isSelected = true;
    //}

    // TODO: See if it is actually needed to get the quantity of packed lines

    //If the user created a single occurrence to represent
    //multiple occurrences, get the quantity
    int n = 1;
    boolean packed = currentComponent.isPacked();
    if (!packed) {
        try {
            //String str = icbl.getProperty("bl_quantity");
            String str = TXDExportAction.getBOMLineProperty(currentComponent, "bl_quantity");
            if (str != null) {
                n = Integer.parseInt(str);
            }
        } catch (NumberFormatException e) {
            //Do nothing
        }
    }

    Debug.println("PERF: Inside printXMLTag: Reading BOMLine props  complete");

    //TODO: See why this is in a loop, and if it is necessary
    XMLStringBuffer buf = new XMLStringBuffer();

    //Loop over the BOM line n times
    for (int count = 0; count < n ; count++) {
        //Build the opening XML entry
        //XMLStringBuffer buf = new XMLStringBuffer();
        buf.startTag(TXDExportAction.BOMLINE);
        buf.appendAttribute(TXDExportAction.ITEM_ID, itemID);
        buf.appendAttribute(TXDExportAction.REV_ID, revID);

        buf.appendAttribute(TXDExportAction.PDM_OCC_ID, pdmOccID);
        buf.appendAttribute(TXDExportAction.ITEM_SELECTED, isSelected);

        // If this is not the lowest level tag, don't put in the slash at the end.
        // If it is, close the tag.
        //TODO: Remove writing of tags, add to the BOMElement.write function.
        //if (closureTags == 0){
        //  buf.endTagBracket();
        //}
        //else{
        //  buf.endTag();

        //  //Handle closure tags for parents
        //    for(int i = 0; i < closureTags; i++){
        //      buf.endTag(BOMLINE);
        //    }
        //}


    }
    buf.endTagBracket();

    // Step 3: write a </bomline> tag at the same level
    fromPortalTXTFile.print(level);
    fromPortalTXTFile.println(buf);
    //buf.endTag(TXDExportAction.BOMLINE);

    if (!childBOMElements.isEmpty()){
        // Step 1: print tag + information
        level = level + "    ";
        // Step 2: for each child, call child.write()
        for (; counter < childBOMElements.size();){
            counter ++;
            //BOMElement nextElement = childBOMElements.get(index);
            counter = childBOMElements.get(counter - 1).write(fromPortalTXTFile, level, counter); 
        }
        // </Bomline> tag
        //fromPortalTXTFile.println(buf.endTag(TXDExportAction.BOMLINE));
    }
    else
    {
        // If no children, close the tag with a leaflet
        //fromPortalTXTFile.println(buf);
        counter++;
        fromPortalTXTFile.print(buf.endTag());
    }


    // For some reason, using a recursive function in a for loop resets the counter of the for loop.
    // The only work-around is to pass the counter back as a return method.
    return counter;
}

【问题讨论】:

  • 你没有足够的右括号,一方面......你是否期望递归调用中的递增计数器传播给调用者?如果是这样,那就不会发生了:在 Java 中,参数是按值传递的。
  • 他确实说了基本逻辑。也就是说,演示文稿中存在各种错误,将在此处要求一个实际的代码测试示例。
  • 我没有复制粘贴代码,我输入了伪代码来简化阅读它的人,这样他们就不必解析数百行不相关的代码。我可以告诉你文件中的语法是正确的,并将更正示例。
  • childrenList 中有什么?您确定要传递 childrenList[counter-1] 而不仅仅是 counter-1?
  • 所以,函数调用不可能是正确的,不是吗?因为childrenList[counter-1] 不是整数。逻辑似乎有问题。

标签: java loops recursion


【解决方案1】:

这是因为您在调用递归方法之前增加了counter(这就是为什么在递归调用中需要counter - 1 并且完全冗余)。

也就是说,您遇到的问题在于您的一般构造。您正在传入计数器并定义每个计数器值的循环。但是,子对象不能保证具有其父对象的子对象数量。父母 A 有 3 个孩子,因此您传入的 counter 的值为 0、1 或 2。但是,如果孩子 A 本身只有 1 个孩子,那么 1 或 2 的 counter 将导致它失败(出现 IndexOutOfBounds 错误)。

public void write(PrintWriter fromPortalTXTFile, String level) {

    . . . 

    if(children) {
        for(int n = 0; n < childrenList.size(); n++) {
            // you need to pass in the child object, unless 
            // you're controlling it with level
            write(childrenList.get(n), level);
        }
    } else {

        . . .

    }
}

请记住,这不会是完美的。我无权访问您的整个代码。不知道在做什么水平。我不知道你是怎么得到 childrenList 的。

但是你把事情复杂化了。如果孩子存在,您需要做的就是为每个孩子递归。

编辑:来自评论链:

您可能没有正确处理根文档的子级。要么,要么你有一个无限循环,因为它永远重新启动 for 循环(所以 n 将始终为 0)。您可以通过查看 level 是否正确递增(或递减)来进行测试。

因此,上述示例并不是完整的答案。处理您如何处理子对象是解决方案的一部分。

【讨论】:

  • 这不起作用,如上述问题所述。当使用以下循环结构时: for(int n = 0; n
  • 我无权访问您的整个程序。我所能做的就是指出您现有逻辑的问题。对不起,如果这没有帮助! -- EDIT:循环计数器不应该重置,因为它只有一个本地范围。您的代码中可能还有其他问题。
  • 您提供的示例代码无法单独运行,除非这是我在方法之外遇到的一些奇怪问题。由于某种原因,当尝试调用递归方法时,for-loop 计数器会中断。
  • "请记住,这不会是完美的。我无法访问您的整个代码。我不知道在做什么级别。我不知道你是怎么做的'正在获取 childrenList。” - 这可能是我的代码不起作用的原因。除了粘贴整个程序代码之外,您还需要查看差异并找出计数器被重置的位置。这就是问题所在。
  • 它在 for 循环开始时被重置,这通常表现得很奇怪。递归调用后我在循环中的任何代码都不会被调用,它会像第一次被调用一样跳回到循环的开头。
猜你喜欢
  • 1970-01-01
  • 2017-10-26
  • 1970-01-01
  • 1970-01-01
  • 2019-08-21
  • 2023-03-26
  • 2013-09-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多