Jika saya punya List<List<Object>>
, bagaimana saya bisa mengubahnya menjadi List<Object>
yang berisi semua objek dalam urutan iterasi yang sama dengan menggunakan fitur Java 8?
Jika saya punya List<List<Object>>
, bagaimana saya bisa mengubahnya menjadi List<Object>
yang berisi semua objek dalam urutan iterasi yang sama dengan menggunakan fitur Java 8?
Jawaban:
Anda bisa menggunakan flatMap
untuk meratakan daftar internal (setelah mengubahnya menjadi Streaming) menjadi satu Stream, dan kemudian mengumpulkan hasilnya menjadi daftar:
List<List<Object>> list = ...
List<Object> flat =
list.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
Class::method
terasa sedikit aneh pada awalnya, tetapi memiliki manfaat bahwa ia menyatakan jenis objek yang Anda pemetaan. Jika tidak demikian, itu adalah sesuatu yang Anda kehilangan dalam aliran.
The flatMap
metode pada Stream
kaleng tentu meratakan daftar tersebut untuk Anda, tetapi harus membuat Stream
objek untuk elemen, makaStream
untuk hasil.
Anda tidak perlu semua Stream
benda itu. Berikut adalah kode ringkas dan ringkas untuk melakukan tugas tersebut.
// listOfLists is a List<List<Object>>.
List<Object> result = new ArrayList<>();
listOfLists.forEach(result::addAll);
Karena List
ini Iterable
, kode ini panggilan yang forEach
metode (Java 8 fitur), yang diwarisi dari Iterable
.
Lakukan tindakan yang diberikan untuk setiap elemen
Iterable
hingga semua elemen diproses atau tindakan melempar pengecualian. Tindakan dilakukan dalam urutan iterasi, jika urutan itu ditentukan.
Dan List
's Iterator
kembali item secara berurutan.
Untuk Consumer
, kode ini meneruskan referensi metode (fitur Java 8) ke metode pra-Java 8 List.addAll
untuk menambahkan elemen daftar bagian dalam secara berurutan.
Tambahkan semua elemen dalam koleksi yang ditentukan ke akhir daftar ini, dalam urutan bahwa mereka dikembalikan oleh iterator koleksi yang ditentukan (operasi opsional).
Anda dapat menggunakan flatCollect()
pola dari Eclipse Collections .
MutableList<List<Object>> list = Lists.mutable.empty();
MutableList<Object> flat = list.flatCollect(each -> each);
Jika Anda tidak dapat mengubah daftar dari List
:
List<List<Object>> list = new ArrayList<>();
List<Object> flat = ListAdapter.adapt(list).flatCollect(each -> each);
Catatan: Saya adalah kontributor untuk Eclipse Collections.
Seperti yang disebutkan oleh @Saravana:
flatmap lebih baik tetapi ada cara lain untuk mencapai hal yang sama
listStream.reduce(new ArrayList<>(), (l1, l2) -> {
l1.addAll(l2);
return l1;
});
Singkatnya, ada beberapa cara untuk mencapai hal yang sama sebagai berikut:
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);
}
Saya hanya ingin menjelaskan satu skenario lebih seperti List<Documents>
, daftar ini berisi daftar yang lebih beberapa dokumen lain seperti List<Excel>
, List<Word>
, List<PowerPoint>
. Jadi strukturnya
class A {
List<Documents> documentList;
}
class Documents {
List<Excel> excels;
List<Word> words;
List<PowerPoint> ppt;
}
Sekarang jika Anda ingin mengulangi Excel hanya dari dokumen kemudian lakukan sesuatu seperti di bawah ini ..
Jadi kodenya
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.
}
Saya harap ini dapat memecahkan masalah seseorang saat ...
Kami dapat menggunakan flatmap untuk ini, silakan lihat kode di bawah ini:
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);
Perluasan jawaban Eran yang merupakan jawaban teratas, jika Anda memiliki banyak lapisan daftar, Anda dapat terus memetakannya.
Ini juga dilengkapi dengan cara pemfilteran yang praktis saat Anda membuka lapisan jika diperlukan juga.
Jadi misalnya:
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())
Ini akan serupa dalam SQL untuk memiliki pernyataan SELECT dalam pernyataan SELECT.
Metode untuk mengonversi a List<List>
menjadi List
:
listOfLists.stream().flatMap(List::stream).collect(Collectors.toList());
Lihat contoh ini:
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);
}
}
Mencetak:
listOfLists => [[a, b, c]]
list => [a, b, c]
::
:)