【问题标题】:Recursively iterate through nested list递归遍历嵌套列表
【发布时间】:2021-09-19 01:08:52
【问题描述】:

我想实现一个递归函数,它遍历列表中对象的子列表,并将子列表中的所有元素添加到一个大列表中。

我的对象如下:

List 带有一个名为 .getDependsOn() 的函数的任务,该函数返回它所依赖的 List

从一个依赖于任务 B 的任务开始,然后又依赖于任务 C 和 D,我想递归地遍历每个任务并将它们添加到一个大列表中,其中包括任务 A 的每个依赖任务.

public List<Task> addDependencies(List<Task> tasks) {
  for (Task task: tasks) {
   if (!task.getDependsOn().isEmpty()) {
    tasks.addAll(addDependencies(task.getDependsOn()));
    return tasks;
   } else {
    return tasks;
   }
  }
  return tasks;
}

这是我尝试过的,但它不起作用,因为它会引发 InvocationTargetException。我正在尝试解决我的问题,尝试在我的大脑中调试它大约 2 小时,但无法解决。

【问题讨论】:

  • 看来您混淆了输入列表和输出列表,因为您的方法采用输入参数,修改它并返回相同的引用,这简直是多余的。您要修改原始列表还是要在新列表中提供结果?
  • 1.请提供 InvocationTargetException 的完整堆栈跟踪,2. 请添加示例以重现异常。

标签: java list algorithm recursion


【解决方案1】:

我认为您的异常正在发生,因为您试图在迭代列表时同时追加列表。如果我明白你想要做什么,也许这样的事情会起作用

public List<Task> addDependencies(List<Task> tasks) {
  List<Task> subTaskList = new ArrayList<Task>;
  for (Task task: tasks) {
   if (!task.getDependsOn().isEmpty())
    subTaskList.addAll(addDependencies(task.getDependsOn()));
  }
  tasks.addAll(subTaskList);
  return tasks;
}

【讨论】:

    【解决方案2】:

    你的方法中的一些问题:

    1. task.getDependsOn() 为空时,您只需返回tasks,这会忽略剩余的task 依赖项,您应该改为调用continue
    2. 您在调用addDependencies(task.getDependsOn()) 时没有复制,这会产生意想不到的副作用(更改task.getDependsOn())。

    我更喜欢使用带有flatMap 的Stream 来解决这个问题,因为它不会产生副作用,而且我们不需要创建许多List 副本。

    public static Stream<Task> flattenDependencies(List<Task> tasks) {
        return tasks.stream().flatMap(task -> {
            Stream<Task> flattened = flattenDependencies(task.getDependsOn());
            return Stream.concat(Stream.of(task), flattened);
        });
    }
    

    完整示例
    主类

    import java.util.List;
    import java.util.stream.Collectors;
    import java.util.stream.Stream;
    
    public class FlattenTask {
        public static void main(String[] args) {
            Task a = new Task("a");
            Task b = new Task("b");
            Task c = new Task("c");
            Task d = new Task("d");
            Task e = new Task("e");
            Task f = new Task("f");
            a.setDependsOn(List.of(b, c));
            b.setDependsOn(List.of(d, e));
            List<Task> tasks = List.of(a, f);
            System.out.println(flattenDependencies(tasks).collect(Collectors.toList()).toString());
        }
    
        public static Stream<Task> flattenDependencies(List<Task> tasks) {
            return tasks.stream().flatMap(task -> {
                Stream<Task> flattened = flattenDependencies(task.getDependsOn());
                return Stream.concat(Stream.of(task), flattened);
            });
        }
    }
    

    任务

    import java.util.Collections;
    import java.util.List;
    
    public class Task {
    
        private final String code;
        private List<Task> dependsOn = Collections.emptyList();
    
        public Task(String code) {
            this.code = code;
        }
    
        public List<Task> getDependsOn() {
            return dependsOn;
        }
    
        public void setDependsOn(List<Task> dependsOn) {
            this.dependsOn = dependsOn;
        }
    
        @Override
        public String toString() {
            return code;
        }
    }
    

    【讨论】:

    • 谢谢,非常好的回应。除了标准的hackerrank比赛之外,你还有什么资源可以训练我的算法技能(尤其是递归)?
    猜你喜欢
    • 1970-01-01
    • 2019-08-03
    • 2019-08-06
    • 2019-08-22
    • 2023-04-01
    • 2016-04-30
    • 2014-03-01
    • 2015-05-16
    相关资源
    最近更新 更多