Nếu tôi có một List<List<Object>>
, làm thế nào tôi có thể biến nó thành một List<Object>
đối tượng chứa tất cả các đối tượng theo cùng một thứ tự lặp bằng cách sử dụng các tính năng của Java 8?
Nếu tôi có một List<List<Object>>
, làm thế nào tôi có thể biến nó thành một List<Object>
đối tượng chứa tất cả các đối tượng theo cùng một thứ tự lặp bằng cách sử dụng các tính năng của Java 8?
Câu trả lời:
Bạn có thể sử dụng flatMap
để làm phẳng các danh sách nội bộ (sau khi chuyển đổi chúng thành Luồng) thành một Luồng duy nhất và sau đó thu thập kết quả vào một danh sách:
List<List<Object>> list = ...
List<Object> flat =
list.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
Class::method
ban đầu cảm thấy hơi kỳ lạ, nhưng nó có lợi ích là nó tuyên bố loại đối tượng bạn đang ánh xạ từ đâu. Đó là một cái gì đó bạn mất trong dòng.
Các flatMap
phương pháp trên Stream
lon chắc chắn làm phẳng những danh sách cho bạn, nhưng nó phải tạo Stream
đối tượng cho các phần tử, sau đó một Stream
kết quả.
Bạn không cần tất cả những Stream
đối tượng đó. Dưới đây là mã đơn giản, súc tích để thực hiện nhiệm vụ.
// listOfLists is a List<List<Object>>.
List<Object> result = new ArrayList<>();
listOfLists.forEach(result::addAll);
Bởi vì một List
là Iterable
, mã này gọi là các forEach
phương pháp (Java 8 tính năng), được thừa hưởng từ Iterable
.
Thực hiện hành động đã cho cho từng phần tử của
Iterable
cho đến khi tất cả các phần tử đã được xử lý hoặc hành động đưa ra một ngoại lệ. Các hành động được thực hiện theo thứ tự lặp, nếu thứ tự đó được chỉ định.
Và một List
's Iterator
mục lợi nhuận theo thứ tự tuần tự.
Đối với Consumer
, mã này chuyển một tham chiếu phương thức (tính năng Java 8) sang phương thức tiền Java 8 List.addAll
để thêm các phần tử danh sách bên trong một cách tuần tự.
Nối tất cả các phần tử trong bộ sưu tập đã chỉ định vào cuối danh sách này, theo thứ tự chúng được trả về bởi trình lặp của bộ sưu tập đã chỉ định (thao tác tùy chọn).
Bạn có thể sử dụng flatCollect()
mẫu từ Bộ sưu tập Eclipse .
MutableList<List<Object>> list = Lists.mutable.empty();
MutableList<Object> flat = list.flatCollect(each -> each);
Nếu bạn không thể thay đổi danh sách từ List
:
List<List<Object>> list = new ArrayList<>();
List<Object> flat = ListAdapter.adapt(list).flatCollect(each -> each);
Lưu ý: Tôi là người đóng góp cho Bộ sưu tập Eclipse.
Giống như @Saravana đã đề cập:
Flatmap là tốt hơn nhưng có nhiều cách khác để đạt được điều tương tự
listStream.reduce(new ArrayList<>(), (l1, l2) -> {
l1.addAll(l2);
return l1;
});
Tóm lại, có một số cách để đạt được như sau:
private <T> List<T> mergeOne(Stream<List<T>> listStream) {
return listStream.flatMap(List::stream).collect(toList());
}
private <T> List<T> mergeTwo(Stream<List<T>> listStream) {
List<T> result = new ArrayList<>();
listStream.forEach(result::addAll);
return result;
}
private <T> List<T> mergeThree(Stream<List<T>> listStream) {
return listStream.reduce(new ArrayList<>(), (l1, l2) -> {
l1.addAll(l2);
return l1;
});
}
private <T> List<T> mergeFour(Stream<List<T>> listStream) {
return listStream.reduce((l1, l2) -> {
List<T> l = new ArrayList<>(l1);
l.addAll(l2);
return l;
}).orElse(new ArrayList<>());
}
private <T> List<T> mergeFive(Stream<List<T>> listStream) {
return listStream.collect(ArrayList::new, List::addAll, List::addAll);
}
Tôi chỉ muốn giải thích một kịch bản giống như List<Documents>
, danh sách này có chứa một vài danh sách chi tiết của các tài liệu khác như List<Excel>
, List<Word>
, List<PowerPoint>
. Vì vậy, cấu trúc là
class A {
List<Documents> documentList;
}
class Documents {
List<Excel> excels;
List<Word> words;
List<PowerPoint> ppt;
}
Bây giờ nếu bạn chỉ muốn lặp lại Excel từ các tài liệu thì hãy làm một cái gì đó như dưới đây ..
Vì vậy, mã sẽ là
List<Documents> documentList = new A().getDocumentList();
//check documentList as not null
Optional<Excel> excelOptional = documentList.stream()
.map(doc -> doc.getExcel())
.flatMap(List::stream).findFirst();
if(excelOptional.isPresent()){
Excel exl = optionalExcel.get();
// now get the value what you want.
}
Tôi hy vọng điều này có thể giải quyết vấn đề của ai đó trong khi mã hóa ...
Chúng tôi có thể sử dụng bản đồ phẳng cho việc này, vui lòng tham khảo mã dưới đây:
List<Integer> i1= Arrays.asList(1, 2, 3, 4);
List<Integer> i2= Arrays.asList(5, 6, 7, 8);
List<List<Integer>> ii= Arrays.asList(i1, i2);
System.out.println("List<List<Integer>>"+ii);
List<Integer> flat=ii.stream().flatMap(l-> l.stream()).collect(Collectors.toList());
System.out.println("Flattened to List<Integer>"+flat);
Một bản mở rộng về câu trả lời của Eran là câu trả lời hàng đầu, nếu bạn có một loạt các lớp danh sách, bạn có thể giữ sơ đồ hóa chúng.
Điều này cũng đi kèm với một cách lọc tiện dụng khi bạn đi xuống các lớp nếu cần thiết.
Ví dụ:
List<List<List<List<List<List<Object>>>>>> multiLayeredList = ...
List<Object> objectList = multiLayeredList
.stream()
.flatmap(someList1 -> someList1
.stream()
.filter(...Optional...))
.flatmap(someList2 -> someList2
.stream()
.filter(...Optional...))
.flatmap(someList3 -> someList3
.stream()
.filter(...Optional...))
...
.collect(Collectors.toList())
Điều này sẽ tương tự trong SQL khi có các câu lệnh CHỌN trong các câu lệnh CHỌN.
Phương pháp chuyển đổi List<List>
thành List
:
listOfLists.stream().flatMap(List::stream).collect(Collectors.toList());
Xem ví dụ này:
public class Example {
public static void main(String[] args) {
List<List<String>> listOfLists = Collections.singletonList(Arrays.asList("a", "b", "v"));
List<String> list = listOfLists.stream().flatMap(List::stream).collect(Collectors.toList());
System.out.println("listOfLists => " + listOfLists);
System.out.println("list => " + list);
}
}
Nó in:
listOfLists => [[a, b, c]]
list => [a, b, c]
::
:)