Como classificar uma Lista <Objeto> em ordem alfabética usando o campo Nome do objeto

102

Eu tenho uma lista de objetos como List<Object> p. Quero classificar essa lista em ordem alfabética usando o campo Nome do objeto. O objeto contém 10 campos e o campo de nome é um deles.

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

Mas não há nada como String.compare ..?

Saurabh Kumar
fonte
3
Como você vai conseguir o nome? - Objects não têm nomes. Você quer dizer usar .toString()?
Matt Fenwick
object1e object2precisa ser do tipo Campaign, e a função de comparação é object1.getName().compareTo(object2.getName()).
Bart van Heukelom
Você mistura List<Object>e Comparator<Campaign>. Você não pode fazer isso. Ou você tem List<Object>e Comparator<Object>ou List<Campaign>eComparator<Campaign>
viktor

Respostas:

230

Pelo seu código, parece que seu Comparatorjá está parametrizado com Campaign. Isso só funcionará com List<Campaign>. Além disso, o método que você está procurando é 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 se você estiver usando Java 1.8

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

Um comentário final - não adianta verificar o tamanho da lista. Classificar funcionará em uma lista vazia.

Robert B
fonte
2
Acho que essa é a melhor resposta que destila tudo no que o OP está procurando. E a partir dos comentários, acho que ele quer não diferenciar maiúsculas de minúsculas, então apenas mude o compareTo para compareToIgnoreCase
Greg Case
Pequena melhora na primeira solução: podemos fazer if (list.size ()> 1) - quanto a 1 item, não há necessidade de classificar ..
Rami Yampolsky
12
Você pode usarComparator.comparing(Campaign::getName)
Jose Da Silva
4
list.sort((object1, object2) -> object1. getName().compareTo(object2. getName()));trabalhou para mim
Lucas
1
Tente usar sortedList = list.stream().sort((object1, object2) -> object1. getName().compareTo(object2. getName()))..collect(Collectors.toList());para obter uma nova lista classificada
Lukas
16

A maneira mais correta de classificar strings em ordem alfabética é usar Collator, por causa da internacionalização. Alguns idiomas têm ordem diferente devido a alguns caracteres extras 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());
        }
       });
   }

Se você não se preocupa com a internacionalização, use 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
fonte
11

Dê uma olhada em Collections.sort()e na Comparatorinterface.

A comparação de strings pode ser feita com object1.getName().compareTo(object2.getName())ouobject2.getName().compareTo(object1.getName()) (dependendo da direção de classificação desejada).

Se você quiser que o tipo seja agnóstico, faça object1.getName().toUpperCase().compareTo(object2.getName().toUpperCase()).

Tobiasbayer
fonte
e como você sugere extrair esse campo chamado namado Objecttipo? esta resposta não está completa.
Amit
A extração de nome depende do tipo de objeto. Suponho que seja apenas um tipo de espaço reservado. Se você não pode dar um tipo mais concreto, você pode acabar usando reflexão.
tobiasbayer
9

Usando Java 8 Comparator.comparing :

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

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

}

Substitua Object pela sua classe que contém o campo de nome

Uso:

ObjectComparator comparator = new ObjectComparator();
Collections.sort(list, comparator);
Jan Vorcak
fonte
Eu fiz isso, mas "testes" virá antes de "Pesquisar".: (((
Saurabh Kumar
se você quiser fazer a classificação reversa, basta substituir obj1.getName().compareTo(obj2.getName()por obj2.getName().compareTo(obj1.getName()na classe de comparação
janeiro 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
fonte
2

Aqui está uma versão da resposta de Robert B que funciona para List<T>e classificando por uma propriedade String especificada do objeto usando Reflection e nenhuma biblioteca de terceiros

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

Você pode usar as coleçõessortThisBy() do Eclipse :

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

Se você não pode alterar o tipo de lista de List:

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

Nota: Sou um contribuidor das Coleções Eclipse.

Nikhil Nanivadekar
fonte
2

Experimente isto:

List< Object> myList = x.getName;
myList.sort(Comparator.comparing(Object::getName));
Alper Karaağaçlı
fonte
Para sua informação, se você estiver fazendo isso no Android, é necessário pelo menos API de nível 24
MSpeed ​​de
1

Se seus objetos têm algum ancestral comum [que seja T], você deve usar em List<T>vez de List<Object>, e implementar um Comparador para este T, usando o campo de nome.

Se você não tiver um ancestral comum, pode implementar um Comperator e usar reflexão para extrair o nome. Observe que não é seguro, não é sugerido e sofre de mau desempenho usar reflexão, mas permite que você acesse um nome de campo sem saber nada sobre o tipo real do objeto [além do fato de que ele tem um campo com o nome relevante]

Em ambos os casos, você deve usar Collections.sort () para classificar.

amit
fonte
1

Encontrei outra maneira de fazer o tipo.

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

Isso pressupõe uma lista de em YourClassvez de Object, conforme explicado por amit .

Você pode usar este bit da biblioteca Google Guava:

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

As demais respostas que mencionam Comparatornão são incorretas, pois Orderingimplementa Comparator. Esta solução é, na minha opinião, um pouco mais fácil, embora possa ser mais difícil se você for um iniciante e não estiver acostumado a usar bibliotecas e / ou "programação funcional".

Copiado descaradamente desta resposta à minha própria pergunta.

Bart van Heukelom
fonte
É assim que eu faria, mas pode ser demais para o OP.
Greg Case
0

Usando uma classificação de seleção

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
fonte
(1) Por que ele reinventaria a roda? o que há de errado Collections.sort()? (2) a lista é do tipo List<Object>e, portanto list.get(j).getName(), não será compilada. (3) esta solução é O (n ^ 2), enquanto o uso Collections.sort()é uma solução O (nlogn) melhor.
Amit
0

Se você estiver usando um List<Object>para conter objetos de um subtipo que tem um campo de nome (vamos chamar o subtipo NamedObject), você precisará reduzir os elementos da lista para acessar o nome. Você tem 3 opções, a melhor das quais é a primeira:

  1. Não use um List<Object>em primeiro lugar se você puder evitar - mantenha seus objetos nomeados em umList<NamedObject>
  2. Copie seus List<Object>elementos em um List<NamedObject>downcasting no processo, faça a classificação e copie-os de volta
  3. Faça o downcasting no Comparador

A opção 3 seria assim:

Collections.sort(p, new Comparator<Object> () {
        int compare (final Object a, final Object b) {
                return ((NamedObject) a).getName().compareTo((NamedObject b).getName());
        }
}
Mike E
fonte
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
fonte
1
Importa-se de elaborar, em vez de apenas despejar o código em uma pergunta de 3 anos?
Holloway
0

A resposta de @ Victor funcionou para mim e publicá-la novamente aqui em Kotlin para o caso de ser útil para alguém que está fazendo 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
fonte