Table of Contents
Laboratorium 9 - Województwa, powiaty, gminy - sortowanie i filtrowanie
Zapoznaj się z treścią wykładów dotyczących:
- Mogą się także przydać informacje o Typach generycznych
Sortujemy listę jednostek administracyjnych
Listy w Java mają funkcję sort()
, której argumentem jest Comparator<T>
referencja do klasy zapewniającej funkcję do porównywania elementów public int compare(T t, T t1)
.
Funkcja powinna zwrócić
- wartość ujemną, jeżeli w wyniku sortowania 't' ma się znaleźć przed 't1'
- 0, jeżeli elementy są równe
- wartość dodatnią, jeżeli 't' ma się znaleźć po 't1'
Użyj lokalnej nazwanej klasy wewnętrznej
Napisz funkcję sortInplaceByName()
. Wewnątrz zdefiniuj klasę dziedziczącą po Comparator<AdminUnit>
. utwórz obiekt tej klasy i przekaż do funkcji sort()
/** * Sortuje daną listę jednostek (in place = w miejscu) * @return this */ AdminUnitList sortInplaceByName(){ ... }
Użyj lokalnej klasy anonimowej
Napisz funkcję używając w niej lokalnej klasy anonimowej (zdefiniowanej w locie jako new Comparator<AdminUnit>(){…}
).
/** * Sortuje daną listę jednostek (in place = w miejscu) * @return this */ AdminUnitList sortInplaceByArea(){ ... }
Użyj wyrażenia lambda
Patrz Wyrażenia lambda i strumienie przykład na stronie 13
Napisz funkcję korzystając z wyrażenia lambda
/** * Sortuje daną listę jednostek (in place = w miejscu) * @return this */ AdminUnitList sortInplaceByPopulation(){ ... }
Piszemy bardziej ogólne funkcje
Zaimplementuj funkcje
AdminUnitList sortInplace(Comparator<AdminUnit> cmp){ // return this; }
oraz
AdminUnitList sort(Comparator<AdminUnit> cmp){ // Tworzy wyjściową listę // Kopiuje wszystkie jednostki // woła sortInPlace }
Filtrowanie
Użyjemy interfejsu Predicate a zwłaszcza jego metody test()
.
Napisz
/** * * @param pred referencja do interfejsu Predicate * @return nową listę, na której pozostawiono tylko te jednostki, * dla których metoda test() zwraca true */ AdminUnitList filter(Predicate<AdminUnit> pred){
Poeksperymentuj z różnymi warunkami.
Np. kod, który wyświetla jednostki o nazwach na “Ż” posortowane według powierzchni może wyglądać następująco
list.filter(a->a.name.startsWith("Ż")).sortByArea().list(out);
Napisz:
- wybór (i sortowanie) elementów zaczynających się na “K”
- wybór jednostek będących powiatami, których
parent.name
to województwo małopolskie - zaproponuj kilka podobnych kryteriów selekcji
Interfejs Predicate<T>
ma metody (standardowe implementacje metod) and
or
oraz negate
. Zaproponuj kryteria selekcji używające tych funkcji
Oczywiście za każdym razem możesz używać klas anonimowych w stylu
Predicate<AdminUnit> p = new Predicate(){ // i tu naciśnij Alt Enter
albo krótszych wyrażeń lambda.
Ograniczanie liczby wyjściowych elementów
Zaimplementuj filtrowanie z parametrem limit
/** * Zwraca co najwyżej limit elementów spełniających pred * @param pred - predykat * @param limit - maksymalna liczba elementów * @return nową listę */ AdminUnitList filter(Predicate<AdminUnit> pred, int limit){ throw new RuntimeException("Not implemented yet") }
Zaimplementuj również funkcję:
/** * Zwraca co najwyżej limit elementów spełniających pred począwszy od offset * Offest jest obliczany po przefiltrowaniu * @param pred - predykat * @param - od którego elementu * @param limit - maksymalna liczba elementów * @return nową listę */ AdminUnitList filter(Predicate<AdminUnit> pred, int offset, int limit){ throw new RuntimeException("Not implemented yet") }
… czyli dla wywołania filter(pred,100,50)
spośród 138 spełniających predykat pred
wypisze te o indeksach 100-137.
Ale nie bardzo chcemy zastosować rozwiązanie: utwórz nową listę za pomocą filter(pred) i wybierz z niej elementy…
AdminUnitQuery
Napisz stosunkowo prostą klasę AdminUnitQuery
skupiającą specyfikację (i wykonanie) tych wszystkich operacji
public class AdminUnitQuery { AdminUnitList src; Predicate<AdminUnit> p = a->true; Comparator<AdminUnit> cmp; int limit = Integer.MAX_VALUE; int offset = 0; /** * Ustawia listę jako przetwarzane źródło * @param src * @return this */ AdminUnitQuery selectFrom(AdminUnitList src){ ... } /** * * @param pred - ustawia predykat p * @return this */ AdminUnitQuery where(Predicate<AdminUnit> pred){ ... } /** * Wykonuje operację p = p and pred * @param pred * @return this */ AdminUnitQuery and(Predicate<AdminUnit> pred){ ... } /** * Wykonuje operację p = p or pred * @param pred * @return this */ AdminUnitQuery or(Predicate<AdminUnit> pred){ ... } /** * Ustawia komparator cmp * @param cmp * @return this */ AdminUnitQuery sort(Comparator<AdminUnit> cmp){ ... } /** * Ustawia limit * @param limit * @return this */ AdminUnitQuery limit(int limit){ ... } /** * Ustawia offset * @param offset * @return this */ AdminUnitQuery offset(int offset){ ... } /** * Wykonuje zapytanie i zwraca wynikową listę * @return przefiltrowana i opcjonalnie posortowana lista (uwzględniamy także offset/limit) */ AdminUnitList execute(){ ... } }
Przetestuj uzupełniony kod w zapytaniach typu:
AdminUnitQuery query = new AdminUnitQuery() .selectFrom(list) .where(a->a.area>1000) .or(a->a.name.startsWith("Sz")) .sort((a,b)->Double.compare(a.area,b.area)) .limit(100); query.execute().list(out);
Napisz 3 własne propozycje zapytań