Cómo ordenar una lista <Objeto> alfabéticamente usando el campo de nombre de objeto

103

Tengo una lista de objetos como List<Object> p. Quiero ordenar esta lista alfabéticamente usando el campo de nombre de objeto. El objeto contiene 10 campos y el campo de nombre es uno de ellos.

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());
        }
    } );
}

Pero no hay nada como String.compare ..?

Saurabh Kumar
fuente
3
¿Cómo vas a conseguir el nombre? - ObjectNo tengo nombres. ¿Te refieres a usar .toString()?
Matt Fenwick
object1y object2debe ser de tipo Campaign, y la función de comparación es object1.getName().compareTo(object2.getName()).
Bart van Heukelom
Mezclas List<Object>y Comparator<Campaign>. No puedes hacer eso. O tienes List<Object>y Comparator<Object>o List<Campaign>eComparator<Campaign>
Viktor

Respuestas:

231

A partir de su código, parece que Comparatorya está parametrizado con Campaign. Esto solo funcionará con List<Campaign>. Además, el método que está buscando es 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());
      }
  });
}

O si está utilizando Java 1.8

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

Un comentario final: no tiene sentido verificar el tamaño de la lista. Ordenar funcionará en una lista vacía.

Robert B
fuente
2
Creo que esta es la mejor respuesta que destila todo en lo que está buscando el OP. Y a partir de los comentarios, creo que quiere que no se distinga entre mayúsculas y minúsculas, así que simplemente cambie el compareTo a compareToIgnoreCase
Greg Case
Mejora menor en la primera solución: podemos hacer if (list.size ()> 1) - como para 1 elemento no es necesario ordenar ..
Rami Yampolsky
12
Puede usarComparator.comparing(Campaign::getName)
Jose Da Silva
4
list.sort((object1, object2) -> object1. getName().compareTo(object2. getName()));trabajó para mí
Lucas
1
Intente usar sortedList = list.stream().sort((object1, object2) -> object1. getName().compareTo(object2. getName()))..collect(Collectors.toList());para obtener una nueva lista ordenada
Lukas
16

La forma más correcta de ordenar alfabéticamente cadenas es usar Collator, debido a la internacionalización. Algunos idiomas tienen un orden diferente debido a algunos caracteres adicionales, 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 no le importa el uso de la internacionalización 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
fuente
11

Echar un vistazo a Collections.sort(), y elComparator interfaz.

La comparación de cadenas se puede realizar con object1.getName().compareTo(object2.getName())o object2.getName().compareTo(object1.getName())(según la dirección de clasificación que desee).

Si desea que el tipo sea independiente del caso, hágalo object1.getName().toUpperCase().compareTo(object2.getName().toUpperCase()).

tobiasbayer
fuente
y ¿cómo sugiere extraer ese campo llamado namadel Objecttipo? esta respuesta no es completa.
amit
La extracción de nombres depende del tipo de objeto. Supuse que es solo un tipo de marcador de posición. Si no puede dar un tipo más concreto, puede terminar usando la reflexión.
tobiasbayer
7
public class ObjectComparator implements Comparator<Object> {

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

}

Reemplace el objeto con su clase que contiene el campo de nombre

Uso:

ObjectComparator comparator = new ObjectComparator();
Collections.sort(list, comparator);
Jan Vorcak
fuente
Hice esto, pero las "pruebas" vienen antes de "Buscar".: (((
Saurabh Kumar
si desea hacer una clasificación inversa, simplemente reemplace obj1.getName().compareTo(obj2.getName()con obj2.getName().compareTo(obj1.getName()en la clase de comparador
Jan Vorcak
2

algo como

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

Aquí hay una versión de la respuesta de Robert B que funciona List<T>y ordena por una propiedad String especificada del objeto usando Reflection y sin bibliotecas de terceros

/**
 * 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
fuente
2

Puede usar sortThisBy()de Eclipse Collections :

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

Si no puede cambiar el tipo de lista de List:

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

Nota: Soy colaborador de Eclipse Collections.

Nikhil Nanivadekar
fuente
2

Prueba esto:

List< Object> myList = x.getName;
myList.sort(Comparator.comparing(Object::getName));
Alper Karaağaçlı
fuente
Para su información, si está haciendo esto en Android, requiere al menos un nivel de API 24
MSpeed
1

Si sus objetos tienen algún ancestro común [déjelo ser T], debe usar en List<T>lugar de List<Object>e implementar un Comparador para esta T, usando el campo de nombre.

Si no tiene un ancestro común, puede implementar un Comperator y usar la reflexión para extraer el nombre.Tenga en cuenta que no es seguro, no se sugiere y tiene un mal rendimiento para usar la reflexión, pero le permite acceder a un nombre de campo. sin saber nada sobre el tipo real del objeto [además del hecho de que tiene un campo con el nombre relevante]

En ambos casos, debe usar Collections.sort () para ordenar.

amit
fuente
1

Encontré otra forma de escribir.

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

Esto supone una lista de en YourClasslugar de Object, como explica amit .

Puede usar este bit de la biblioteca de Google Guava:

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

Las otras respuestas que mencionan Comparatorno son incorrectas, ya que Orderingimplementa Comparator. Esta solución es, en mi opinión, un poco más fácil, aunque puede ser más difícil si eres un principiante y no estás acostumbrado a usar bibliotecas y / o "programación funcional".

Copiado descaradamente de esta respuesta a mi propia pregunta.

Bart van Heukelom
fuente
Esta es la forma en que lo haría, pero puede ser demasiado para el OP.
Greg Case
0

Usando una selección Ordenar

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
fuente
(1) ¿Por qué iba a reinventar la rueda? lo que está mal con el Collections.sort()? (2) la lista es de tipo List<Object>y, por list.get(j).getName()lo tanto , no se compilará. (3) esta solución es O (n ^ 2), mientras que usar Collections.sort()es una mejor solución O (nlogn).
amit
0

Si está utilizando List<Object>para contener objetos de un subtipo que tiene un campo de nombre (llamemos al subtipo NamedObject), necesitará abatir los elementos de la lista para acceder al nombre. Tienes 3 opciones, la mejor de las cuales es la primera:

  1. List<Object>En primer lugar, no use un si puede evitarlo; mantenga los objetos con nombre en unList<NamedObject>
  2. Copie sus List<Object>elementos en un List<NamedObject>, reduciendo en el proceso, haga la clasificación y luego cópielos de nuevo
  3. Hacer el downcasting en el comparador

La opción 3 se vería así:

Collections.sort(p, new Comparator<Object> () {
        int compare (final Object a, final Object b) {
                return ((NamedObject) a).getName().compareTo((NamedObject b).getName());
        }
}
Mike E
fuente
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
fuente
1
¿Le gustaría elaborar en lugar de simplemente descargar el código en una pregunta de 3 años?
Holloway
0

La respuesta de @ Victor funcionó para mí y volver a publicarla aquí en Kotlin en caso de que sea útil para otra persona que usa 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
fuente