web-dev-qa-db-fra.com

Java - Liste distincte d'objets

J'ai une liste/collection d'objets qui peuvent ou non avoir les mêmes valeurs de propriété. Quelle est la manière la plus simple d'obtenir une liste distincte d'objets ayant des propriétés égales? Un type de collection convient-il le mieux à cette fin? Par exemple, en C #, je pourrais faire quelque chose comme ceci avec LINQ.

var recipients = (from recipient in recipientList
                 select recipient).Distinct();

Ma pensée initiale était d'utiliser lambdaj ( texte du lien ), mais il ne semble pas le supporter.

28
javacavaj

Utilisez une implémentation de l'interface Set<T> (La classe T peut avoir besoin d'une méthode .equals() personnalisée, et vous devrez peut-être implémenter cette .equals() vous-même). Généralement, un HashSet le fait immédiatement: il utilise la méthode Object.hashCode() et Object.equals() pour comparer les objets. Cela devrait être assez unique pour les objets simples. Sinon, vous devrez implémenter T.equals() et T.hashCode() en conséquence.

Voir le commentaire de Gaurav Saini ci-dessous pour les bibliothèques aidant à implémenter equals et hashcode.

28
glmxndr
return new ArrayList(new HashSet(recipients));
39
Chase Seibert

Placez-les dans un TreeSet qui contient un comparateur personnalisé, qui vérifie les propriétés dont vous avez besoin:

SortedSet<MyObject> set = new TreeSet<MyObject>(new Comparator<MyObject>(){

    public int compare(MyObject o1, MyObject o2) {
         // return 0 if objects are equal in terms of your properties
    }
});

set.addAll(myList); // eliminate duplicates
20
Robert Munteanu

Java 8:

recipients = recipients.stream()
    .distinct()
    .collect(Collectors.toList());

Voir Java.util.stream.Stream#distinct .

11
Dexter Legaspi

ordre préservant la version de la réponse ci-dessus

return new ArrayList(new LinkedHashSet(recipients));
9
rudnev

Si vous utilisez Collections Eclipse , vous pouvez utiliser la méthode distinct().

ListIterable<Integer> integers = Lists.mutable.with(1, 3, 1, 2, 2, 1);
Assert.assertEquals(
    Lists.mutable.with(1, 3, 2),
    integers.distinct());

L'avantage d'utiliser distinct() au lieu de convertir en ensemble puis de revenir en liste est que distinct() préserve l'ordre de la liste d'origine, en conservant la première occurrence de chaque élément. Il est implémenté en utilisant à la fois un ensemble et une liste.

MutableSet<T> seenSoFar = Sets.mutable.with();
int size = list.size();
for (int i = 0; i < size; i++)
{
    T item = list.get(i);
    if (seenSoFar.add(item))
    {
        targetCollection.add(item);
    }
}
return targetCollection;

Si vous ne pouvez pas convertir votre liste d'origine en un type de collections Eclipse, vous pouvez utiliser ListAdapter pour obtenir la même API.

MutableList<Integer> distinct = ListAdapter.adapt(integers).distinct();

Remarque: je suis un committer pour les collections Eclipse.

7
Craig P. Motlin

Vous pouvez utiliser un Set. Il y a quelques implémentations:

  • HashSet utilise hashCode et equals d'un objet.
  • TreeSet utilise compareTo (défini par Comparable) ou compare (défini par Comparator). Gardez à l'esprit que la comparaison doit être cohérente avec equals. Voir TreeSet JavaDocs pour plus d'informations.

Gardez également à l'esprit que si vous remplacez equals, vous devez remplacer hashCode de sorte que deux objets égaux aient le même code de hachage.

4
Steve Kuo

La façon ordinaire de procéder serait de convertir en un ensemble, puis de revenir à une liste. Mais vous pouvez vous faire plaisir avec Java fonctionnel . Si vous avez aimé Lamdaj, vous allez adorer FJ.

recipients = recipients
             .sort(recipientOrd)
             .group(recipientOrd.equal())
             .map(List.<Recipient>head_());

Vous devrez avoir défini un ordre pour les destinataires, recipientOrd. Quelque chose comme:

Ord<Recipient> recipientOrd = ord(new F2<Recipient, Recipient, Ordering>() {
  public Ordering f(Recipient r1, Recipient r2) {
    return stringOrd.compare(r1.getEmailAddress(), r2.getEmailAddress());
  }
});

Fonctionne même si vous n'avez pas le contrôle de equals() et hashCode() sur la classe Recipient.

3
Apocalisp

En fait, lambdaj implémente cette fonctionnalité via la méthode selectDistinctArgument

http://lambdaj.googlecode.com/svn/trunk/html/apidocs/ch/lambdaj/Lambda.html#selectDistinctArgument (Java.lang.Object,% 20A)

2
Mario Fusco