it-swarm.com.de

Java List.contains (Objekt mit Feldwert gleich x)

Ich möchte prüfen, ob eine List ein Objekt enthält, das ein Feld mit einem bestimmten Wert hat. Jetzt konnte ich eine Schleife verwenden, um durchzugehen und zu überprüfen, aber ich war gespannt, ob es etwas effizienteres für den Code gibt. 

So etwas wie;

if(list.contains(new Object().setName("John"))){
    //Do some stuff
}

Ich weiß, dass der obige Code nichts tut, er soll nur ungefähr zeigen, was ich erreichen möchte.

Der Grund, aus dem ich keine einfache Schleife verwenden möchte, ist, dass dieser Code derzeit in eine Schleife geht, die sich in einer Schleife befindet, die sich in einer Schleife befindet. Aus Gründen der Lesbarkeit möchte ich nicht ständig weitere Loops hinzufügen. Also habe ich mich gefragt, ob es einfache (ish) Alternativen gibt.

137
Rudi Kershaw

Streams

Wenn Sie Java 8 verwenden, können Sie Folgendes versuchen:

public boolean containsName(final List<MyObject> list, final String name){
    return list.stream().filter(o -> o.getName().equals(name)).findFirst().isPresent();
}

Alternativ können Sie auch so etwas versuchen:

public boolean containsName(final List<MyObject> list, final String name){
    return list.stream().map(MyObject::getName).filter(name::equals).findFirst().isPresent();
}

Diese Methode gibt true zurück, wenn der List<MyObject> eine MyObject mit dem Namen name enthält. Wenn Sie eine Operation für jede der MyObjects dieser getName().equals(name) ausführen möchten, können Sie Folgendes versuchen:

public void perform(final List<MyObject> list, final String name){
    return list.stream().filter(o -> o.getName().equals(name)).forEach(
            o -> {
                //...
            }
    );
}

Dabei steht o für eine MyObject-Instanz.

169
Josh M

Sie haben zwei Möglichkeiten.

1. Die erste Wahl, die zu bevorzugen ist, besteht darin, die Methode `equals () 'in Ihrer Object-Klasse zu überschreiben.

Angenommen, Sie haben beispielsweise diese Objektklasse:

public class MyObject {
    private String name;
    private String location;
    //getters and setters
}

Nehmen wir an, Sie kümmern sich nur um den Namen des MyObject, dh es sollte eindeutig sein. Wenn also zwei MyObjects denselben Namen haben, sollten sie als gleich angesehen werden. In diesem Fall möchten Sie die Methode `equals () '(und auch die Methode' hashcode () ') überschreiben, damit die Namen zur Bestimmung der Gleichheit verglichen werden.

Wenn Sie dies getan haben, können Sie überprüfen, ob eine Collection ein MyObject mit dem Namen "foo" enthält.

MyObject object = new MyObject();
object.setName("foo");
collection.contains(object);

Dies ist jedoch möglicherweise keine Option für Sie, wenn:

  • Sie verwenden sowohl den Namen als auch den Ort, um die Gleichheit zu prüfen, Sie möchten jedoch nur prüfen, ob eine Collection über `MyObject`s mit einem bestimmten Ort verfügt. In diesem Fall haben Sie equals () bereits überschrieben.
  • `MyObject` ist Teil einer API, die Sie nicht ändern dürfen.

In beiden Fällen sollten Sie die Option 2 wählen:

2. Schreiben Sie Ihre eigene Utility-Methode:

public static boolean containsLocation(Collection<MyObject> c, String location) {
    for(MyObject o : c) {
        if(o != null && o.getLocation.equals(location)) {
            return true;
        }
    }
    return false;
}

Alternativ können Sie ArrayList (oder eine andere Auflistung) erweitern und dann Ihre eigene Methode hinzufügen:

public boolean containsLocation(String location) {
    for(MyObject o : this) {
        if(o != null && o.getLocation.equals(location)) {
                return true;
            }
        }
        return false;
    }

Leider gibt es keinen besseren Weg.

73
James Dunn

Google Guava

Wenn Sie Guava verwenden, können Sie einen funktionalen Ansatz wählen und Folgendes tun

FluentIterable.from(list).find(new Predicate<MyObject>() {
   public boolean apply(MyObject input) {
      return "John".equals(input.getName());
   }
}).Any();

das sieht ein wenig wortreich aus. Das Prädikat ist jedoch ein Objekt und Sie können verschiedene Varianten für verschiedene Suchvorgänge bereitstellen. Beachten Sie, wie die Bibliothek selbst die Iteration der Sammlung und die Funktion, die Sie anwenden möchten, trennt. Sie müssen equals() nicht für ein bestimmtes Verhalten überschreiben.

Wie unten erwähnt, bietet das in Java 8 und später integrierte Java.util.Stream - Framework etwas Ähnliches.

24
Brian Agnew

Collection.contains() wird implementiert, indem equals() für jedes Objekt aufgerufen wird, bis eines von true zurückgegeben wird.

Eine Möglichkeit, dies zu implementieren, besteht darin, equals() zu überschreiben, aber natürlich können Sie nur ein Gleiches haben.

Frameworks wie Guava verwenden hierfür Prädikate. Mit Iterables.find(list, predicate) können Sie nach beliebigen Feldern suchen, indem Sie den Test in das Prädikat einfügen.

Andere Sprachen, die auf VM basieren, haben dies eingebaut. In Groovy zum Beispiel schreiben Sie einfach:

def result = list.find{ it.name == 'John' }

Java 8 hat uns auch unser Leben leichter gemacht:

List<Foo> result = list.stream()
    .filter(it -> "John".equals(it.getName())
    .collect(Collectors.toList());

Wenn Sie sich für solche Dinge interessieren, schlage ich das Buch "Beyond Java" vor. Es enthält viele Beispiele für die zahlreichen Mängel von Java und wie andere Sprachen besser abschneiden.

18
Aaron Digulla

Binäre Suche

Sie können Collections.binarySearch verwenden, um ein Element in Ihrer Liste zu durchsuchen (vorausgesetzt, die Liste ist sortiert):

Collections.binarySearch(list, new YourObject("a1", "b",
                "c"), new Comparator<YourObject>() {

            @Override
            public int compare(YourObject o1, YourObject o2) {
                return o1.getName().compareTo(o2.getName());
            }
        });

dies gibt eine negative Zahl zurück, wenn das Objekt nicht in der Auflistung vorhanden ist. Andernfalls wird die index des Objekts zurückgegeben. Damit können Sie nach Objekten mit unterschiedlichen Suchstrategien suchen.

17
Debojit Saikia

Karte

Sie könnten einen Hashmap<String, Object> erstellen, indem Sie einen der Werte als Schlüssel verwenden und dann sehen, ob yourHashMap.keySet().contains(yourValue) true zurückgibt.

7
user7110558

So machen Sie es mit Java 8+:

boolean johnExistance = list.stream().anyMatch(o -> o.getName().equals("John"));
6
GabrielBB

Eclipse-Sammlungen

Wenn Sie Eclipse Collections verwenden, können Sie die anySatisfy()-Methode verwenden. Passen Sie entweder Ihre List in eine ListAdapter an oder ändern Sie Ihre List in eine ListIterable, wenn möglich.

ListIterable<MyObject> list = ...;

boolean result =
    list.anySatisfy(myObject -> myObject.getName().equals("John"));

Wenn Sie solche Operationen häufig ausführen, ist es besser, eine Methode zu extrahieren, die angibt, ob der Typ das Attribut hat.

public class MyObject
{
    private final String name;

    public MyObject(String name)
    {
        this.name = name;
    }

    public boolean named(String name)
    {
        return Objects.equals(this.name, name);
    }
}

Sie können das alternative Formular anySatisfyWith() zusammen mit einer Methodenreferenz verwenden.

boolean result = list.anySatisfyWith(MyObject::named, "John");

Wenn Sie Ihre List nicht in eine ListIterable umwandeln können, verwenden Sie ListAdapter wie folgt.

boolean result = 
    ListAdapter.adapt(list).anySatisfyWith(MyObject::named, "John");

Hinweis: Ich bin ein Committer für Eclipse-Kollektionen.

6
Craig P. Motlin

Predicate

Wenn Sie nicht Java 8 oder eine Bibliothek verwenden, die mehr Funktionen für den Umgang mit Sammlungen bietet, können Sie etwas implementieren, das wiederverwendbar ist als Ihre Lösung.

interface Predicate<T>{
        boolean contains(T item);
    }

    static class CollectionUtil{

        public static <T> T find(final Collection<T> collection,final  Predicate<T> predicate){
            for (T item : collection){
                if (predicate.contains(item)){
                    return item;
                }
            }
            return null;
        }
    // and many more methods to deal with collection    
    }

ich benutze so etwas, ich habe ein Prädikat-Interface, und ich übergebe die Implementierung an meine util-Klasse.

Was ist der Vorteil, dies auf meine Art zu tun? Sie haben eine Methode, die die Suche in einer beliebigen Typensammlung behandelt. Sie müssen keine separaten Methoden erstellen, wenn Sie nach anderen Feldern suchen möchten. Alles was Sie tun müssen, ist ein anderes Prädikat, das zerstört werden kann, sobald es nicht mehr nützlich ist.

wenn Sie es verwenden möchten, müssen Sie lediglich die Methode call aufrufen und Ihr Prädikat definieren

CollectionUtil.find(list, new Predicate<MyObject>{
    public boolean contains(T item){
        return "John".equals(item.getName());
     }
});
5
user902383

Die contains-Methode verwendet intern equals. Daher müssen Sie die equals-Methode für Ihre Klasse je nach Bedarf überschreiben.

Übrigens sieht das nicht syntaktisch korrekt aus: 

new Object().setName("John")
2
Juned Ahsan

Hier ist eine Lösung mit Guava

private boolean checkUserListContainName(List<User> userList, final String targetName){

    return FluentIterable.from(userList).anyMatch(new Predicate<User>() {
        @Override
        public boolean apply(@Nullable User input) {
            return input.getName().equals(targetName);
        }
    });
}
2
Linh

Wenn Sie diese List.contains(Object with field value equal to x) wiederholt ausführen müssen, wäre eine einfache und effiziente Problemumgehung:

List<field obj type> fieldOfInterestValues = new ArrayList<field obj type>;
for(Object obj : List) {
    fieldOfInterestValues.add(obj.getFieldOfInterest());
}

Dann hätte List.contains(Object with field value equal to x) dasselbe Ergebnis wie fieldOfInterestValues.contains(x);

1
Magda

Trotz Java 8 SDK gibt es viele Sammlungstools, mit denen Bibliotheken arbeiten können, zum Beispiel: http://commons.Apache.org/proper/commons-collections/

Predicate condition = new Predicate() {
   boolean evaluate(Object obj) {
        return ((Sample)obj).myField.equals("myVal");
   }
};
List result = CollectionUtils.select( list, condition );
0
Pasha Gharibi