Hãy xem xét các lớp sau đây:sử dụng đệ quy của Stream.flatMap()
public class Order {
private String id;
private List<Order> orders = new ArrayList<>();
@Override
public String toString() {
return this.id;
}
// getters & setters
}
LƯU Ý: Điều quan trọng cần lưu ý rằng tôi không thể sửa đổi lớp này, bởi vì tôi đang tiêu thụ nó từ một bên ngoài API.
Cũng xem xét hệ thống phân cấp sau đây của đơn đặt hàng:
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));
Mà có thể được biểu thị theo cách này:
1
1.1
1.1.1
1.2
2
2.1
2.2
2.3
Bây giờ, tôi muốn san bằng hệ thống cấp bậc này của đơn đặt hàng vào một List
, do đó Tôi nhận được các thông tin sau:
[1, 1.1, 1.1.1, 1.2, 2, 2.1, 2.2, 2.3]
Tôi đã quản lý làm điều đó bằng cách đệ quy sử dụng flatMap()
(cùng với một lớp helper), như sau:
List<Order> flattened = orders.stream()
.flatMap(Helper::flatten)
.collect(Collectors.toList());
Đây là lớp 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
}
}
Các dòng sau:
System.out.println(flattened);
Tạo sự sản lượng sau:
[1, 1.1, 1.1.1, 1.2, 2, 2.1, 2.2, 2.3]
Cho đến nay rất tốt. Kết quả là hoàn toàn chính xác.
Tuy nhiên, after reading this question, tôi có một số lo ngại về việc sử dụng flatMap()
trong một phương pháp đệ quy. Đặc biệt, tôi muốn biết cách luồng được mở rộng (nếu đó là thuật ngữ). Vì vậy, tôi biến đổi lớp Helper
và sử dụng peek(System.out::println)
để kiểm tra này:
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);
}
}
Và kết quả là:
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
Tôi không chắc chắn nếu điều này là sản phẩm đó sẽ được in.
Vì vậy, tôi tự hỏi liệu có thể cho phép luồng trung gian chứa các yếu tố lặp lại hay không. Hơn nữa, những ưu và nhược điểm của phương pháp này là gì? Có đúng không, sau khi tất cả, sử dụng flatMap()
theo cách này? Có cách nào tốt hơn để đạt được điều tương tự không?
Chỉ tò mò: tại sao bạn đặt id sau khi tạo thứ tự thay vì biến nó trở thành đối số cho hàm tạo? – sprinter
@sprinter Tôi không thể sửa đổi lớp 'Order' vì nó là một phần của API mà tôi đang sử dụng. –
Ah tôi hiểu rồi. Sau đó, hầu hết câu trả lời của tôi là khá vô ích. Nó có thể là giá trị thêm rằng phần thông tin cho câu hỏi của bạn. – sprinter