当前位置: 首页 > 知识库问答 >
问题:

Stream.FlatMap()的递归使用

蒲魁
2023-03-14

请考虑以下类:

public class Order {

    private String id;

    private List<Order> orders = new ArrayList<>();

    @Override
    public String toString() {
        return this.id;
    }

    // getters & setters
}

注意:很重要的一点是,我不能修改这个类,因为我是从外部API中使用它的。

还要考虑以下订单层次结构:

Order o1 = new Order();
o1.setId("1");
Order o11 = new Order();
o11.setId("1.1");
Order o111 = new Order();
o111.setId("1.1.1");
List<Order> o11Children = new ArrayList<>(Arrays.asList(o111));
o11.setOrders(o11Children);

Order o12 = new Order();
o12.setId("1.2");
List<Order> o1Children = new ArrayList<>(Arrays.asList(o11, o12));
o1.setOrders(o1Children);

Order o2 = new Order();
o2.setId("2");
Order o21 = new Order();
o21.setId("2.1");
Order o22 = new Order();
o22.setId("2.2");
Order o23 = new Order();
o23.setId("2.3");
List<Order> o2Children = new ArrayList<>(Arrays.asList(o21, o22, o23));
o2.setOrders(o2Children);

List<Order> orders = new ArrayList<>(Arrays.asList(o1, o2));
1
1.1
1.1.1
1.2
2
2.1
2.2
2.3
[1, 1.1, 1.1.1, 1.2, 2, 2.1, 2.2, 2.3]

通过递归地使用flatmap()(以及一个helper类),我已经设法做到了这一点,如下所示:

List<Order> flattened = orders.stream()
    .flatMap(Helper::flatten)
    .collect(Collectors.toList());

这是helper类:

public final class Helper {

    private Helper() {
    }

    public static Stream<Order> flatten(Order order) {
        return Stream.concat(
            Stream.of(order), 
            order.getOrders().stream().flatMap(Helper::flatten)); // recursion here
    }
}

以下一行:

System.out.println(flattened);

产生以下输出:

[1, 1.1, 1.1.1, 1.2, 2, 2.1, 2.2, 2.3]

到目前为止还不错。结果是绝对正确的。

但是,在阅读了这个问题之后,我对flatmap()在递归方法中的用法有些担心。特别是,我想知道流是如何被扩展的(如果这是术语的话)。因此,我修改了helper类,并使用peek(System.out::println)检查以下内容:

public static final class Helper {

    private Helper() {
    }

    public static Stream<Order> flatten(Order order) {
        return Stream.concat(
            Stream.of(order), 
            order.getOrders().stream().flatMap(Helper::flatten))
        .peek(System.out::println);
    }
}

结果是:

1
1.1
1.1
1.1.1
1.1.1
1.1.1
1.2
1.2
2
2.1
2.1
2.2
2.2
2.3
2.3

我不确定这是否是应该打印的输出。

共有1个答案

澹台逸明
2023-03-14

嗯,我在一个泛型tree类中使用了相同的模式,并没有产生错误的感觉。唯一的区别是,tree类本身提供了children()allDescendes()方法,这两个方法都返回了stream,后者建立在前者的基础上。这与“我应该返回一个集合还是一个流?”和“命名返回流的java方法”有关。

的角度来看,对于不同类型的子级的FlatMap(即在遍历属性时)和对于相同类型的子级的FlatMap没有区别。如果返回的流再次包含相同的元素也没有问题,因为流的元素之间没有关系。原则上,您可以使用FlatMap作为Filter操作,使用模式FlatMap(x->condition?stream.of(x):stream.empty())。也可以使用它来复制像这个答案中的元素。

 类似资料:
  • 我得到了三个整数操作: A-将3添加到number B-将数字 C加倍-交换number 的最后两位数字我应该编写算法来检查我是否可以在n步中使用操作A、B、C制作k素数。最后,我必须打印我用来制作k素数的操作序列。让我们假设我们有函数: 当数字为素数时,函数ifprime返回true,否则返回false。 代码: 我的问题是,我不知道如何记住正确的路径,然后打印出来。

  • 我有,我只想有一个。我尝试使用,但它不起作用,因为它无法将SortedSet的流扁平化。

  • 问题内容: 我必须用Java编写幂方法。它接收两个整数,无论​​它们是正数还是负数都没有关系。它应该具有的复杂度。它还必须使用递归。我当前的代码有两个数字,但我不断输出的结果是零,我不知道为什么。 问题答案: 让我们从一些数学事实开始: 对于正n,aⁿ=a⨯a⨯…⨯an次 对于负数n,aⁿ=⅟a⁻ⁿ=⅟(a⨯a⨯…⨯a)。这意味着 a 不能为零。 对于n = 0,即使 a 为零或负,aⁿ= 1 。

  • 我写了下面的代码来反转链表的前K个节点,它在反转链表的前K个节点时解决了一些问题,为什么递归在最后一次迭代中执行两次,现在它可以正常工作,但为什么它会导致链表中的循环当我尝试在“if”条件下使用变量“k”而不是“PresCouner”时,原因是什么?以及如何避免它?

  • 我试图了解如何将各种递归函数转换为尾递归。我已经查看了许多将斐波那契和阶乘转换为尾递归的示例,并理解了这些示例,但很难跳到具有某种不同结构的问题。一个例子是: 如何将其转换为尾部递归实现? 我已经看过类似的问题,例如:将正常递归转换为尾部递归,但这些似乎并没有转化为这个问题。

  • 我对函数式编程很陌生,尤其是下面使用的Scheme。我正在尝试使以下函数是递归的,尾递归的。基本上,该函数的作用是对两个字符串的对齐方式进行评分。当给定两个字符串作为输入时,它会比较每个“列”字符,并根据在称为 scorer 的函数中实现的评分方案(由下面的代码中的函数调用)来累积该对齐的分数。 我有一个想法,用一个帮助函数来累积分数,但我不太确定如何去做,因此我该如何让下面的函数尾递归呢?