Probleme beim Filtern über Predicate

bugbunny

Mitglied
Hallo,
ich komme leider wieder einmal nicht weiter.
Ich habe in einer Klasse Spielerbestand folgende Methode:

Java:
 public Set<Player> getPlayers(Predicate<Player> filter)
{
    Set<Player> result = new HashSet<Player>();

    for (Player player : players)
    {
        if (filter.test( player ))
        {
            result.add(player);
        }
    }
    return result;

Nun habe ich noch eine Klasse PlayerFilter, in der verschiedene Filtermöglichkeiten gegeben werden sollen.

Java:
public static Predicate<Player> getLastNameFilter(String lastName)
{    Validate.requireNonNullNotEmpty( lastname );
    return player -> player.getMetadata().getLastName().orElse( "" ).equals( lastName );
}

Das funktioniert noch, aber jetzt soll ich noch 2 Methoden schreiben die die Filter kombinieren.
public static Predicate<Player> combineAnd(Collection<Predicate<Player>> filters)

Es wird eine Collection der definierten Filter übergeben und Spieler zurückgegeben die alle übergebenen Filter erfüllen(AND) bzw. mindestens einen(OR)

Das man predicates mit .and kombinieren kann habe ich gesehen, aber versteht nicht wie ich das auf die variable Collection anwenden könnte.

Grüße Leonie
 

Robat

Top Contributor
Hier mal ein kleines Beispiel anhand von Integern.
Java:
List<Predicate<Integer>> predicates = List.of(e -> e % 2 == 0, e -> e > 2);
List<Integer> values = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
values.stream().filter(predicates.stream().reduce(Predicate::and).orElse(t -> true)).forEach(System.out::println);

Predicate::and kann man dann auch mit Predicate::or tauschen.
 

bugbunny

Mitglied
Danke für das Beispiel, allerdings kann ich es nicht übertragen.:confused:

List<Predicate<Integer>> predicates
=Liste mit den Filtern
Meine Methode bekommt eine Collection übergeben, also erstelle ich in der Methode eine neue Liste und übergebe der die Werte der Collection oder?

List<Integer> values
Eine Liste mit den Inhalten der Integer.
Wäre in meinem Fall also eine Liste vom Typ Spieler?
Also brauche ich eine 2. Liste mit allen Spielern?

Ich habe eine Methode
public Set<Player> getPlayers in der Klasse Spielerbestand die ein Hashset von Spielern zurückgibt, müsste ich die dann der 2. Liste übergeben?
Kann es nicht ausprobieren, da ich aus der Filterklasse gar nicht auf die Methode zugreifen kann?

Beziehungsweise müsste ich dazu ja ein Objekt vom Typ Spielerbestand in der Methode erzeugen, ist ja sicher nicht so gedacht oder?

Grüße
 
Zuletzt bearbeitet:

looparda

Top Contributor
Danke für das Beispiel, allerdings kann ich es nicht übertragen.:confused:
Du musst in Robat's Beispiel wirklich nur noch alles von Integer auf Player umstellen und das wars.
Statt List<Integer> values benutzt du dann halt Set<Player> um konform mit deiner Methode Set<Player> getPlayers() zu sein.
Momentan werden die Elemente, die durch den Filter gekommen sind ausgegeben - die kannst du natürlich stattdessen aufsammeln und dann hast du deine Ergebnisliste mit den gefilterten Elementen.
 
Zuletzt bearbeitet:

looparda

Top Contributor
Java:
public static Collection<Player> combineAnd(List<Predicate<Player>> predicates, Collection<Player> collection) {
    return collection.stream().filter(predicates.stream().reduce(Predicate::and).orElse(t -> true)).collect(Collectors.toList());
}

Warum heißt das Ding eigentlich combineAnd und nicht filterAnd?
 

bugbunny

Mitglied
ich darf die übergebenen Parameter der methode nicht ändern, die Methode muss
Java:
public static Predicate<Player> combineAnd(Collection<Predicate<Player>> filters)
sein.
 

looparda

Top Contributor
Dann wird es so gemeint sein:
Java:
final Collection<Player> filteredPlayers = filter(predicates, values);
filteredPlayers.forEach(System.out::println);
[...]

public static Collection<Player> filter(List<Predicate<Player>> predicates, Collection<Player> collection) {
    return collection.stream().filter(combineAnd(predicates)).collect(Collectors.toList());
}
public static Predicate<Player> combineAnd(Collection<Predicate<Player>> filters) {
    return filters.stream().reduce(Predicate::and).orElse(t -> true);
}
 

bugbunny

Mitglied
Die Vorgabe dazu lautet:
"Für die Methode getPlayerByFilter(Predicate<Player> filter) der
Klasse Spielerbestand lassen sich auch Filter vordefinieren.
Implementieren Sie dazu die Klasse PlayerFilterFactory, die einige statische Methoden zur Verfügung stellt, um Filter zu erzeugen und durch und oder oder zu verknüpfen."
Die schaut bei mir so aus:
Java:
public Set<Player> getPlayers(Predicate<Player> filter)
{
    Set<Player> result = new HashSet<Player>();

    for (Player player : players)
    {
        if (filter.test( player ))
        {
            result.add(player);
        }
    }
    return result;
}

"public static Predicate<Player> combineAnd(Collection<Predicate<Player>>
filters)
Gibt einen Filter zurück, der einen Spieler genau dann akzeptiert, wenn er alle in der übergebenen Collection enthaltenen Filter akzeptiert.Ist die übergebene Collection leer, soll eine java.lang.IllegalArgumentException geworfen werden.
Tipp: Nutzen Sie die Default-Methode and der Schnittstelle Predicate."

Deswegen sollte es meinem "Verständnis" nach ohne die zusätzliche public static Collection<Player> filter funktionieren oder verstehe ich das falsch?
 

Robat

Top Contributor
Deine getPlayers() Methode ersetzt quasi die filter-Methode von @looparda
Du kannst quasi sowas machen:
Java:
Set<Player> filteredPlayers = getPlayers(combineAnd(predicateCollection));
//oder konkreter
List<Predicate<Player>> collection = Arrays.asList(PlayerFilterFactory.predicateMethod1(..), PlayerFilterFactory.predicateMethode2(..));
Set<Player> filteredPlayers = getPlayers(combineAnd(collection));
 

bugbunny

Mitglied
Ich verstehe es einfach nicht :(
Ich kann der Collection mit Arrays.asList doch nicht die einzelnen Filtermethoden übergeben, wenn ich nicht weiß, welche Filter später mal in der Collection sind???
Und auch die getPlayer Methode kann ich doch nicht ohne Objekt nicht verwenden?
Wahnsinn wie kompliziert das ist.
 

Robat

Top Contributor
Woher kommt denn die Collection mit den Predicates? Gibt es da eine vorgefertigte zum testen, kommt die aus deinem Programm, sollst du sie dir selber erstellen? Du musst doch Vorgaben zum testen haben und wenn nicht musst du dir selber Testdaten einfallen lassen.

Das du eine Instanz brauchst um die getPlayers() Methode aufzurufen ist mir bewusst. Wollte nur nicht so viel schreiben, da ich dachte es sei klar ;)
Ich habe das oben nur so geschrieben um dir zu demonstrieren wie du das ganze jetzt verwenden könntest.

Du hast jetzt die combineAnd() Methode + Deine verschiedenen Filtermethoden (in der FilterFactory-Klasse?) und die getPlayers() Methode (in der Spielstand-Klasse [hab den Namen vergessen]).

Dann musst du dir doch jetzt nur noch ein paar Testfälle einfallen lassen.
 

Neue Themen


Oben