Comment trier une liste <Objet> par ordre alphabétique à l'aide du champ Nom de l'objet

103

J'ai une liste d'objets comme. List<Object> pJe veux trier cette liste par ordre alphabétique en utilisant le champ de nom d'objet. L'objet contient 10 champs et le champ de nom en est un.

if (list.size() > 0) {
    Collections.sort(list, new Comparator<Campaign>() {
        @Override
        public int compare(final Object object1, final Object object2) {
        return String.compare(object1.getName(), object2.getName());
        }
    } );
}

Mais il n'y a rien de tel que String.compare ..?

Saurabh Kumar
la source
3
Comment allez-vous obtenir le nom? - Objects n'ont pas de noms. Voulez-vous dire utiliser .toString()?
Matt Fenwick
object1et object2doivent être de type Campaign, et la fonction de comparaison l'est object1.getName().compareTo(object2.getName()).
Bart van Heukelom
Vous mélangez List<Object>et Comparator<Campaign>. Vous ne pouvez pas faire ça. Soit vous avez List<Object>et Comparator<Object>ou List<Campaign>etComparator<Campaign>
viktor

Réponses:

231

D'après votre code, il semble que votre Comparatorsoit déjà paramétré avec Campaign. Cela ne fonctionnera qu'avec List<Campaign>. De plus, la méthode que vous recherchez est compareTo.

if (list.size() > 0) {
  Collections.sort(list, new Comparator<Campaign>() {
      @Override
      public int compare(final Campaign object1, final Campaign object2) {
          return object1.getName().compareTo(object2.getName());
      }
  });
}

Ou si vous utilisez Java 1.8

list
  .stream()
  .sorted((object1, object2) -> object1.getName().compareTo(object2.getName()));

Un dernier commentaire - il ne sert à rien de vérifier la taille de la liste. Le tri fonctionnera sur une liste vide.

Robert B
la source
2
Je pense que c'est la meilleure réponse qui distille tout dans ce que l'OP recherche. Et d'après les commentaires, je pense qu'il veut être insensible à la casse, alors il suffit de basculer le comparateurTo pour comparerToIgnoreCase
Greg Case
Amélioration mineure dans la première solution: on peut faire if (list.size ()> 1) - comme pour 1 item pas besoin de trier ..
Rami Yampolsky
12
Vous pouvez utiliserComparator.comparing(Campaign::getName)
Jose Da Silva
4
list.sort((object1, object2) -> object1. getName().compareTo(object2. getName()));travaillé pour moi
Lucas
1
Essayez d'utiliser sortedList = list.stream().sort((object1, object2) -> object1. getName().compareTo(object2. getName()))..collect(Collectors.toList());pour obtenir une nouvelle liste triée
Lukas
16

La façon la plus correcte de trier les chaînes par ordre alphabétique consiste à utiliser Collator, en raison de l'internationalisation. Certaines langues ont un ordre différent en raison de quelques caractères supplémentaires, etc.

   Collator collator = Collator.getInstance(Locale.US);
   if (!list.isEmpty()) {
    Collections.sort(list, new Comparator<Campaign>() {
        @Override
        public int compare(Campaign c1, Campaign c2) {
            //You should ensure that list doesn't contain null values!
            return collator.compare(c1.getName(), c2.getName());
        }
       });
   }

Si vous ne vous souciez pas de l'utilisation de l'internationalisation string.compare(otherString).

   if (!list.isEmpty()) {
    Collections.sort(list, new Comparator<Campaign>() {
        @Override
        public int compare(Campaign c1, Campaign c2) {
            //You should ensure that list doesn't contain null values!
            return c1.getName().compare(c2.getName());
        }
       });
   }
Viktor
la source
11

Jetez un œil à Collections.sort()et à l' Comparatorinterface.

La comparaison de chaînes peut être effectuée avec object1.getName().compareTo(object2.getName())ou object2.getName().compareTo(object1.getName())(selon le sens de tri souhaité).

Si vous voulez que le tri soit indépendant du cas, faites-le object1.getName().toUpperCase().compareTo(object2.getName().toUpperCase()).

tobiasbayer
la source
et comment suggérez-vous d'extraire ce champ appelé namadu Objecttype? cette réponse n'est pas complète.
amit
L'extraction de nom dépend du type de l'objet. J'ai supposé que c'était juste un type d'espace réservé. Si vous ne pouvez pas donner un type plus concret, vous pouvez arrêter d'utiliser la réflexion.
tobiasbayer
9

Utilisation de Java 8 Comparator.comparing :

list.sort(Comparator.comparing(Campaign::getName));
Oleksandr Pyrohov
la source
7
public class ObjectComparator implements Comparator<Object> {

    public int compare(Object obj1, Object obj2) {
        return obj1.getName().compareTo(obj2.getName());
    }

}

Veuillez remplacer Object par votre classe qui contient le champ de nom

Usage:

ObjectComparator comparator = new ObjectComparator();
Collections.sort(list, comparator);
Jan Vorcak
la source
Je l'ai fait mais que "tests" arrive avant "Search".: (((
Saurabh Kumar
si vous voulez faire un tri inversé, remplacez-le simplement obj1.getName().compareTo(obj2.getName()par obj2.getName().compareTo(obj1.getName()dans la classe de comparaison
Jan Vorcak
2

quelque chose comme

  List<FancyObject> theList =  ;
  Collections.sort (theList,
                    new Comparator<FancyObject> ()
                    { int compare (final FancyObject a, final FancyObject d)
                          { return (a.getName().compareTo(d.getName())); }});
BRPocock
la source
2

Voici une version de la réponse de Robert B qui fonctionne pour List<T>et trie par une propriété String spécifiée de l'objet en utilisant Reflection et aucune bibliothèque tierce

/**
 * Sorts a List by the specified String property name of the object.
 * 
 * @param list
 * @param propertyName
 */
public static <T> void sortList(List<T> list, final String propertyName) {

    if (list.size() > 0) {
        Collections.sort(list, new Comparator<T>() {
            @Override
            public int compare(final T object1, final T object2) {
                String property1 = (String)ReflectionUtils.getSpecifiedFieldValue (propertyName, object1);
                String property2 = (String)ReflectionUtils.getSpecifiedFieldValue (propertyName, object2);
                return property1.compareToIgnoreCase (property2);
            }
        });
    }
}


public static Object getSpecifiedFieldValue (String property, Object obj) {

    Object result = null;

    try {
        Class<?> objectClass = obj.getClass();
        Field objectField = getDeclaredField(property, objectClass);
        if (objectField!=null) {
            objectField.setAccessible(true);
            result = objectField.get(obj);
        }
    } catch (Exception e) {         
    }
    return result;
}

public static Field getDeclaredField(String fieldName, Class<?> type) {

    Field result = null;
    try {
        result = type.getDeclaredField(fieldName);
    } catch (Exception e) {
    }       

    if (result == null) {
        Class<?> superclass = type.getSuperclass();     
        if (superclass != null && !superclass.getName().equals("java.lang.Object")) {       
            return getDeclaredField(fieldName, type.getSuperclass());
        }
    }
    return result;
}
che javara
la source
2

Vous pouvez utiliser à sortThisBy()partir des collections Eclipse :

MutableList<Campaign> list = Lists.mutable.empty();
list.sortThisBy(Campaign::getName);

Si vous ne pouvez pas modifier le type de liste à partir de List:

List<Campaign> list = new ArrayList<>();
ListAdapter.adapt(list).sortThisBy(Campaign::getName);

Remarque: je suis un contributeur aux collections Eclipse.

Nikhil Nanivadekar
la source
2

Essaye ça:

List< Object> myList = x.getName;
myList.sort(Comparator.comparing(Object::getName));
Alper Karaağaçlı
la source
Pour info, si vous faites cela sous Android, cela nécessite au moins le niveau d'API 24
MSpeed
1

Si vos objets ont un ancêtre commun [que ce soit T], vous devriez utiliser à la List<T>place de List<Object>et implémenter un comparateur pour ce T, en utilisant le champ de nom.

Si vous n'avez pas d'ancêtre commun, vous pouvez implémenter un Comperator et utiliser la réflexion pour extraire le nom, notez qu'il est dangereux, non suggéré et souffre de mauvaises performances pour utiliser la réflexion, mais cela vous permet d'accéder à un nom de champ sans rien savoir sur le type réel de l'objet [outre le fait qu'il a un champ avec le nom pertinent]

Dans les deux cas, vous devez utiliser Collections.sort () pour trier.

amit
la source
1

J'ai trouvé une autre façon de faire le type.

if(listAxu.size() > 0){
    Collections.sort(listAxu, Comparator.comparing(IdentityNamed::getDescricao));
}
Rafael Mendes
la source
0

Ceci suppose une liste de YourClassau lieu de Object, comme expliqué par amit .

Vous pouvez utiliser ce bit de la bibliothèque Google Guava:

Collections.sort(list, Ordering.natural()
  .onResultOf(new Function<String,YourClass>() {
  public String call(YourClass o) {
     return o.getName();
  }))
  .nullsLast();

Les autres réponses qui mentionnent Comparatorne sont pas incorrectes, puisque des Orderingoutils Comparator. Cette solution est, à mon avis, un peu plus simple, même si elle peut être plus difficile si vous êtes un débutant et que vous n'êtes pas habitué à utiliser des bibliothèques et / ou une "programmation fonctionnelle".

Copié sans vergogne de cette réponse sur ma propre question.

Bart van Heukelom
la source
C'est comme ça que je le ferais, mais c'est peut-être trop pour l'OP.
Greg Case
0

Utilisation d'une sélection Trier

for(int i = list.size() - 1; i > 0; i--){

  int max = i

  for(int j = 0; j < i; j++){
      if(list.get(j).getName().compareTo(list.get(j).getName()) > 0){
            max= j;
      }
  }

  //make the swap
  Object temp = list.get(i);
  list.get(i) = list.get(max);
  list.get(max) = temp;

}
Shizumaru18
la source
(1) Pourquoi réinventerait-il la roue? quel est le problème Collections.sort()? (2) la liste est de type List<Object>et ne list.get(j).getName()sera donc pas compilée. (3) cette solution est O (n ^ 2), en utilisantCollections.sort() est une meilleure solution O (nlogn).
amit
0

Si vous utilisez un List<Object>pour contenir des objets d'un sous-type qui a un champ de nom (appelons le sous-type NamedObject), vous devrez réduire les éléments de la liste afin d'accéder au nom. Vous avez 3 options, dont la meilleure est la première:

  1. N'utilisez pas a List<Object>en premier lieu si vous pouvez l'aider - conservez vos objets nommés dans unList<NamedObject>
  2. Copiez vos List<Object>éléments dans un List<NamedObject>, downcasting dans le processus, faites le tri, puis recopiez-les
  3. Faites le downcasting dans le comparateur

L'option 3 ressemblerait à ceci:

Collections.sort(p, new Comparator<Object> () {
        int compare (final Object a, final Object b) {
                return ((NamedObject) a).getName().compareTo((NamedObject b).getName());
        }
}
Mike E
la source
0
if(listAxu.size() > 0){
     Collections.sort(listAxu, new Comparator<Situacao>(){
        @Override
        public int compare(Situacao lhs, Situacao rhs) {            
            return lhs.getDescricao().compareTo(rhs.getDescricao());
        }
    });
 }
George Freire
la source
1
Voulez-vous élaborer plutôt que de simplement jeter du code dans une question vieille de 3 ans?
Holloway
0

La réponse de @ Victor a fonctionné pour moi et la republie ici à Kotlin au cas où cela serait utile à quelqu'un d'autre faisant Android.

if (list!!.isNotEmpty()) {
   Collections.sort(
     list,
     Comparator { c1, c2 -> //You should ensure that list doesn't contain null values!
     c1.name!!.compareTo(c2.name!!)
   })
}
Francislainy Campos
la source