Laboratorium 9 - Województwa, powiaty, gminy - sortowanie i filtrowanie
Zapoznaj się z treścią wykładów dotyczących:
- Intefejsów i klas wewnętrznych
- Wyrażeń lambda i strumieni
- 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źć przedt1
- 0, jeżeli elementy są równe
- wartość dodatnią, jeżeli
t
ma się znaleźć pot1
Użyj lokalnej nazwanej klasy wewnętrznej
Napisz funkcję - 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.
/**
* 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")
}
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);