は、次のクラスを考えてみましょう:再帰的使用
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
が、私はそのようにList
に注文のこの階層をフラット化したいが私は以下を取得します:
[1, 1.1, 1.1.1, 1.2, 2, 2.1, 2.2, 2.3]
これは、ヘルパークラスである
List<Order> flattened = orders.stream()
.flatMap(Helper::flatten)
.collect(Collectors.toList());
:次のように、再帰的に(ヘルパークラスと一緒に)flatMap()
を使用することによってそれを行う
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]
これまでのところとても良いです。結果は絶対に正しいです。
しかし、after reading this question、再帰的な方法で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
私はこれを印刷しなければならない出力であるかはわかりません。
中間ストリームに繰り返し要素が含まれるようにしても構いません。さらに、このアプローチの賛否両論は何ですか?結局のところ、この方法でflatMap()
を使用するのは正しいですか?同じことを達成するより良い方法はありますか?
ちょっと不思議なことに、なぜそれをコンストラクタの引数にするのではなく、オーダーを作成した後にidを設定するのですか? – sprinter
@sprinter 'Order'クラスを変更することはできません。これは、消費しているAPIの一部であるためです。 –
ああ、私は参照してください。それから、私の答えのほとんどはかなり役に立たない。あなたの質問にその情報を追加する価値があるかもしれません。 – sprinter