Liste Listesini Java 8'de Listeye nasıl dönüştürebilirim?


532

Eğer varsa , Java 8'in özelliklerini kullanarak bunu aynı yineleme sırasına sahip tüm nesneleri içeren List<List<Object>>bir haline nasıl dönüştürebilirim List<Object>?

Yanıtlar:


950

Sen kullanabilirsiniz flatMaptek Çayı'nın içine (Akışları dönüştürerek sonra) iç listelerini dümdüz ve sonra bir liste halinde sonucunu toplamak için:

List<List<Object>> list = ...
List<Object> flat = 
    list.stream()
        .flatMap(List::stream)
        .collect(Collectors.toList());

11
@arshajii true, ama nedense lambda ifadesini tercih ediyorum. Belki de görünüşünü sevmiyorum :::)
Eran

25
Class::methodilk başta biraz garip hissettiriyor, ancak ne tür bir nesneden eşlediğinizi açıklamanın yararı var. Bu, akarsularda kaybettiğiniz bir şeydir.
ArneHugo

2
Yine de bir List'in kabına sahip olmak isteyebilirsiniz ve bu durumda lambda (l-> l.myList.stream ()) kullanmanız gerekebilir.
Myoch

2
Açık döküm yapmanız gerekiyorsa (örneğin List'e ilkel dizi), lambdas da gerekli olabilir.
Michael Fulton

52

flatmap daha iyidir, ancak bunu başarmanın başka yolları da vardır

List<List<Object>> listOfList = ... // fill

List<Object> collect = 
      listOfList.stream()
                .collect(ArrayList::new, List::addAll, List::addAll);

37

Üzerindeki flatMapyöntem Streambu listeleri sizin için kesinlikle düzleştirebilir, ancak Streamöğe için nesneler, sonra Streamsonuç için bir a oluşturmanız gerekir .

Tüm bu Streamnesnelere ihtiyacınız yok . İşte görevi gerçekleştirmek için basit, özlü kod.

// listOfLists is a List<List<Object>>.
List<Object> result = new ArrayList<>();
listOfLists.forEach(result::addAll);

Bir için Listolan Iterable, bu kod çağırır yöntemi devralınır (Java 8 özelliği), . forEachIterable

IterableTüm öğeler işleninceye veya eylem bir istisna atana kadar her öğesinin verilen eylemini gerçekleştirir . İşlemler, bu sipariş belirtilirse, yineleme sırasında gerçekleştirilir.

Ve a List'nın Iteratoröğeleri sıralı olarak döndürür.

İçin Consumerbu kod List.addAll, iç liste öğelerini sırayla eklemek için Java 8 öncesi yönteme bir yöntem başvurusunda (Java 8 özelliği) geçer .

Belirtilen koleksiyondaki tüm öğeleri, belirtilen koleksiyonun yineleyicisi tarafından döndürülme sırasına göre bu listenin sonuna ekler (isteğe bağlı işlem).


3
Bazı gereksiz tahsisleri önleyen iyi bir alternatif öneri. Bazı büyük koleksiyonlarla çalışırken, bunların nasıl karşılaştırıldığını görmek için bunun en üst yığın kullanımını görmek ilginç olurdu.
Per Lundberg

12

Eclipse Collections'takiflatCollect() kalıbı kullanabilirsiniz .

MutableList<List<Object>> list = Lists.mutable.empty();
MutableList<Object> flat = list.flatCollect(each -> each);

Listeyi şuradan değiştiremiyorsanız List:

List<List<Object>> list = new ArrayList<>();
List<Object> flat = ListAdapter.adapt(list).flatCollect(each -> each);

Not: Eclipse Koleksiyonlarına katkıda bulunuyorum.


21
Java 8 tarafından sağlanan işlevsellik neden üçüncü taraf bağımlılığını kullanıyorsunuz?
saw303

2
Eclipse Collections API koleksiyonun kendisidir, bu nedenle kod özlüdür, bu durumda ana nedenlerden biridir.
Nikhil Nanivadekar

11

@Saravana'nın belirttiği gibi:

flatmap daha iyidir, ancak bunu başarmanın başka yolları da vardır

 listStream.reduce(new ArrayList<>(), (l1, l2) -> {
        l1.addAll(l2);
        return l1;
 });

Özetlemek gerekirse, aşağıdakileri elde etmenin birkaç yolu vardır:

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);
}

11

Sadece bir tane daha senaryo gibi açıklamak istiyorum List<Documents>, bu liste gibi diğer belgelerin birkaç liste içeren List<Excel>, List<Word>, List<PowerPoint>. Yani yapı

class A {
  List<Documents> documentList;
}

class Documents {
  List<Excel> excels;
  List<Word> words;
  List<PowerPoint> ppt;
}

Şimdi Excel'i yalnızca belgelerden yinelemek istiyorsanız, aşağıdaki gibi bir şey yapın ..

Yani kod

 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.
 }

Umarım bu kodlama sırasında birinin sorununu çözebilir ...


1

Bunun için flatmap kullanabiliriz, lütfen aşağıdaki kodlara bakın:

 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);

1

Eran'ın cevabında en büyük cevap olan bir genişleme, eğer bir grup liste katmanınız varsa, onları parçalamaya devam edebilirsiniz.

Bu ayrıca gerektiğinde katmanlardan aşağı inerken kullanışlı bir filtreleme yolu ile birlikte gelir.

Yani mesela:

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())

Bu SQL'de SELECT ifadeleri içinde SELECT ifadelerine sahip olmaya benzer.


1

Yöntem bir dönüştürmek List<List>için List:

listOfLists.stream().flatMap(List::stream).collect(Collectors.toList());

Bu örneğe bakın:

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);
    }

}       

Yazdırır:

listOfLists => [[a, b, c]]
list => [a, b, c]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.