Java8 stream filtrowanie zagniezdzonych list

Java8 stream filtrowanie zagniezdzonych list
shagrin
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Norwegia, Stavanger
1

Hej,
Mam taki obiekt:

Kopiuj
obj {
    //...some properties.... 
    List<> list1 {
       //...some properties....
      List<LocalDate> dates;
    },
    List<> list2{
       //...some properties....
      List<LocalDate> dates;
    },
    List<> list3{
       //...some properties....
      List<LocalDate> dates;
    },
    List<> list4{
       //...some properties....
      List<LocalDate> dates;
    },
}

Jak w ladny sposob moge znalezc najwieksza date z kazdej z list dates, a pozniej najmniejsza z tych znalezionych?

caer
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 465
0

Coś w stylu

Kopiuj
val maxDate1 = list1.stream()
    .flatMap(l -> l.getDates())
    .max(LocalDate::compareTo)
    .get();

Powtórzyć dla reszty list, zebrać do nowej listy i zrobić to samo, tylko z funkcją min?
Ewentualnie przerobić ten obiekt na zwyczajną mapę i pracować po ludzku

shagrin
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Norwegia, Stavanger
0
caer napisał(a):

Coś w stylu

Kopiuj
val maxDate1 = list1.stream()
    .flatMap(l -> l.getDates())
    .max(LocalDate::compareTo)
    .get();

Powtórzyć dla reszty list, zebrać do nowej listy i zrobić to samo, tylko z funkcją min?
Ewentualnie przerobić ten obiekt na zwyczajną mapę i pracować po ludzku

Filtrowanie pojedynczej listy nie jest najmniejszym problemem. Chodzi mi o filtrowanie zagniezdzonych list z obiektu, ktory zawiera kilka list.

caer
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 465
0

No to tak jak mówię, albo zastosować to dla każdej z zagnieżdżonych list albo stworzyć z nich mapę. Niestety Java nie pozwala używać obiektów jak struktur danych, chyba że sięgniesz po refleksję.

Poza tym albo źle zrozumiałem treść pytania albo tam nie ma nic związanego z filtrowaniem

jarekczek
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Siemianowice Śląskie
  • Postów: 500
1
Kopiuj
    ArrayList<List<LocalDate>> listy = new ArrayList<List<LocalDate>>();
    listy.add(obj.list1.dates);
    listy.add(obj.list2.dates);
    listy.add(obj.list3.dates);
    Stream<LocalDate> str = listy.stream()
      .map(L -> L.stream().max(LocalDate::compareTo))
      .filter(Optional::isPresent)
      .map(Optional::get);
    //str.forEach(d -> {System.out.println("data: " + d);});
    System.out.println("min: " + str.min(LocalDate::compareTo));
jarekczek
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Siemianowice Śląskie
  • Postów: 500
1

Sorki, nie zrozumiałem zagnieżdżenia tych list. Ta notacja trochę mnie myli. Ale już chyba kumam.

  1. Nie ma czegoś takiego jak list1.dates, tylko list1.get(0..).dates
  2. Uniknijmy exception, jeżeli żadnej daty nie podano.

Ostatecznie wychodzi mi tak:

Kopiuj
    ArrayList<Stream<LocalDate>> strumienieDat =
      new ArrayList<Stream<LocalDate>>();
    strumienieDat.add(obj.list1.stream().flatMap(L -> L.dates.stream()));
    strumienieDat.add(obj.list2.stream().flatMap(L -> L.dates.stream()));
    strumienieDat.add(obj.list3.stream().flatMap(L -> L.dates.stream()));
    Stream<LocalDate> strumienDat = strumienieDat.stream()
      .map(S -> S.max(LocalDate::compareTo))
      // Mamy strumień typu Optional<LocalDate>, odfiltrujmy puste elementy
      .filter(opt -> opt.isPresent())
      // i wyciągnijmy daty z optionali.
      .map(opt -> opt.get());
    // W strumienDat mamy teraz listę dat maksymalnych z poszczególnych list.
    //strumienDat.forEach(d -> {System.out.println("data: " + d);});
    Optional<LocalDate> optD = strumienDat.min(LocalDate::compareTo);
    if (optD.isPresent())
      System.out.println("min: " + optD.get());

Dzięki za fajne ćwiczenie ze streamów i optionali. :)

Ale tak naprawdę wszystkie pola listN powinny implementować jakiś wspólny interfejs posiadający getDates. Inaczej to chyba błąd projektowy.

EDIT:
Jeszcze rozwiązanie w Groovy, czyli funkcjonalna java z dynamicznymi typami. No bo to najlepszy sposób na te pola dates:

Kopiuj
    def listaListList = [ obj.list1, obj.list2, obj.list3 ]
    def listaMaksDat = listaListList.collect {
      arrayList -> arrayList.collect { o -> o.dates }
                            .flatten { date -> date }
                            .max()
    }
    def data = listaMaksDat.min()
    println "To jest data albo null: $data"
Koziołek
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Stacktrace
  • Postów: 6822
0
Pytanie czy możesz modyfikować oryginalny obiekt? Jeżeli tak, to wystarczy dorzucić do niego coś w rodzaju: ``` public Stream<t> stream(){ return Stream.of(list1, list2, list3).flatMap(List::stream); } ``` i dalej pracujesz z pojedynczym strumieniem. Trochę gorzej jeżeli nie możesz modyfikować oryginalnej klasy, bo wtedy trzeba przenieść generowanie strumienia w miejsce użycia. W każdym razie, sama zamiana obiekty zawierającego kilka pól tego samego typu na strumień z tych pól nie powinna być dużym problemem. Później już wystarczy: ``` dateStream .min(LocalDate::compareTo) .ifPresent(System.out::println); ```

Po doprecyzowaniu:

Kopiuj

Optional<LocalDate> maxFrom(List<<LocalDate> l){
	return l.stream()
		.min(LocalDate::compareTo);
}


Stream.of(maxFrom(lista1), maxFrom(lista2), maxFrom(lista3))
	.filter(Optional::isPresent)
	.map(Optional::get)
	.max(LocalDate::compareTo)

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.