Classificando uma ArrayList de objects usando uma ordem de sorting personalizada

Eu estou olhando para implementar um recurso de sorting para o meu aplicativo de catálogo de endereços.

Eu quero classificar um ArrayList contactArray . Contact é uma class que contém quatro campos: nome, número residencial, número de celular e endereço. Eu quero classificar o name .

Como posso escrever uma function de sorting personalizada para fazer isso?

Aqui está um tutorial sobre como ordenar objects:

  • Os Tutoriais Java – Coleções – Ordenação de Objetos

Embora eu dê alguns exemplos, eu recomendaria lê-lo de qualquer maneira.


Existem várias maneiras de classificar uma ArrayList . Se você quiser definir uma ordem natural (padrão), será necessário permitir que o Contact implemente o Comparable . Supondo que você queira classificar por padrão no name , faça (nullchecks omitido para simplificar):

 public class Contact implements Comparable { private String name; private String phone; private Address address; public int compareTo(Contact other) { return name.compareTo(other.name); } // Add/generate getters/setters and other boilerplate. } 

para que você possa fazer

 List contacts = new ArrayList(); // Fill it. Collections.sort(contacts); 

Se você quiser definir uma ordenação controlável externa (que substitui a ordenação natural), é necessário criar um Comparator :

 List contacts = new ArrayList(); // Fill it. // Now sort by address instead of name (default). Collections.sort(contacts, new Comparator() { public int compare(Contact one, Contact other) { return one.getAddress().compareTo(other.getAddress()); } }); 

Você pode até mesmo definir os Comparator no próprio Contact para que você possa reutilizá-los em vez de recriá-los toda vez:

 public class Contact { private String name; private String phone; private Address address; // ... public static Comparator COMPARE_BY_PHONE = new Comparator() { public int compare(Contact one, Contact other) { return one.phone.compareTo(other.phone); } }; public static Comparator COMPARE_BY_ADDRESS = new Comparator() { public int compare(Contact one, Contact other) { return one.address.compareTo(other.address); } }; } 

que pode ser usado da seguinte forma:

 List contacts = new ArrayList(); // Fill it. // Sort by address. Collections.sort(contacts, Contact.COMPARE_BY_ADDRESS); // Sort later by phone. Collections.sort(contacts, Contact.COMPARE_BY_PHONE); 

E para desnatar, você poderia considerar usar um comparador genérico de javabean :

 public class BeanComparator implements Comparator { private String getter; public BeanComparator(String field) { this.getter = "get" + field.substring(0, 1).toUpperCase() + field.substring(1); } public int compare(Object o1, Object o2) { try { if (o1 != null && o2 != null) { o1 = o1.getClass().getMethod(getter, new Class[0]).invoke(o1, new Object[0]); o2 = o2.getClass().getMethod(getter, new Class[0]).invoke(o2, new Object[0]); } } catch (Exception e) { // If this exception occurs, then it is usually a fault of the developer. throw new RuntimeException("Cannot compare " + o1 + " with " + o2 + " on " + getter, e); } return (o1 == null) ? -1 : ((o2 == null) ? 1 : ((Comparable) o1).compareTo(o2)); } } 

que você pode usar da seguinte maneira:

 // Sort on "phone" field of the Contact bean. Collections.sort(contacts, new BeanComparator("phone")); 

(como você vê no código, possivelmente campos nulos já estão cobertos para evitar NPE durante a sorting)

Além do que já foi postado, você deve saber que, desde o Java 8, podemos encurtar nosso código e escrevê-lo como:

 Collection.sort(yourList, Comparator.comparing(YourClass::getFieldToSortOn)); 

ou desde que a lista agora tem método de sort

 yourList.sort(Comparator.comparing(YourClass::getFieldToSortOn)); 

Explicação:

Desde o Java 8, interfaces funcionais (interfaces com apenas um método abstrato – elas podem ter mais methods padrão ou estáticos) podem ser facilmente implementadas usando:

  • arguments -> body lambdas arguments -> body
  • ou o método referencia source::method .

Já que o Comparator possui apenas um método abstrato int compare(T o1, T o2) , é uma interface funcional.

Então, ao invés de (exemplo da resposta @BalusC )

 Collections.sort(contacts, new Comparator() { public int compare(Contact one, Contact other) { return one.getAddress().compareTo(other.getAddress()); } }); 

podemos reduzir este código para:

 Collections.sort(contacts, (Contact one, Contact other) -> { return one.getAddress().compareTo(other.getAddress()); }); 

Podemos simplificar isso (ou qualquer) lambda pulando

  • tipos de argumentos (o Java irá inferi-los com base na assinatura do método)
  • ou {return}

Então, ao invés de

 (Contact one, Contact other) -> { return one.getAddress().compareTo(other.getAddress(); } 

nós podemos escrever

 (one, other) -> one.getAddress().compareTo(other.getAddress()) 

Também agora o Comparator tem methods estáticos, como comparing(FunctionToComparableValue) ou comparing(FunctionToValue, ValueComparator) que poderíamos usar para criar facilmente Comparadores, que devem comparar alguns valores específicos de objects.

Em outras palavras, podemos rewrite o código acima

 Collections.sort(contacts, Comparator.comparing(Contact::getAddress)); //assuming that Address implements Comparable (provides default order). 

Esta página informa tudo o que você precisa saber sobre a ordenação de collections, como ArrayList.

Basicamente você precisa

  • faça sua class de Contact implementar a interface Comparable por
    • criando um método public int compareTo(Contact anotherContact) dentro dele.
  • Depois de fazer isso, você pode simplesmente chamar Collections.sort(myContactList); ,
    • onde myContactList é ArrayList (ou qualquer outra coleção de Contact ).

Há outra maneira também, envolvendo a criação de uma class de comparação, e você pode ler sobre isso a partir da página vinculada também.

Exemplo:

 public class Contact implements Comparable { .... //return -1 for less than, 0 for equals, and 1 for more than public compareTo(Contact anotherContact) { int result = 0; result = getName().compareTo(anotherContact.getName()); if (result != 0) { return result; } result = getNunmber().compareTo(anotherContact.getNumber()); if (result != 0) { return result; } ... } } 

O BalusC e o bguiz já deram respostas muito completas sobre como usar os Comparadores integrados do Java.

Eu só quero acrescentar que o google-collections tem uma class Ordering que é mais “poderosa” do que os Comparators padrão. Pode valer a pena conferir. Você pode fazer coisas legais, como composição de pedidos, revertendo-os, ordenando dependendo do resultado de uma function para seus objects …

Aqui está uma postagem no blog que menciona alguns de seus benefícios.

Você precisa fazer com que suas classs de contato implementem Comparable e, em seguida, implemente o método compareTo(Contact) . Dessa forma, o Collections.sort poderá classificá-los para você. De acordo com a página à qual vinculei, compareTo ‘retorna um inteiro negativo, zero ou um inteiro positivo, pois esse object é menor, igual ou maior que o object especificado.’

Por exemplo, se você quisesse classificar por nome (de A a Z), sua class ficaria assim:

 public class Contact implements Comparable { private String name; // all the other attributes and methods public compareTo(Contact other) { return this.name.compareTo(other.name); } } 

Ao usar o lambdaj, você pode classificar uma coleção de seus contatos (por exemplo, pelo nome deles) da seguinte maneira

 sort(contacts, on(Contact.class).getName()); 

ou pelo seu endereço:

 sort(contacts, on(Contacts.class).getAddress()); 

e assim por diante. Mais em geral, ele oferece uma DSL para acessar e manipular suas collections de várias maneiras, como filtrar ou agrupar seus contatos com base em algumas condições, agregar alguns dos valores de propriedade, etc.

O Collections.sort é uma boa implementação de sorting. Se você não tiver o equivalente implementado para contato, você precisará passar em uma implementação comparador

De importância:

O algoritmo de sorting é um mergesort modificado (no qual a mesclagem é omitida se o elemento mais alto na sub-lista baixa for menor que o elemento mais baixo na sub-lista alta). Esse algoritmo oferece desempenho n log (n) garantido. A lista especificada deve ser modificável, mas não precisa ser redimensionável. Essa implementação despeja a lista especificada em uma matriz, classifica a matriz e repete a lista redefinindo cada elemento da posição correspondente na matriz. Isso evita o desempenho n2 log (n) resultante da tentativa de classificar uma linked list no local.

A sorting de mesclagem provavelmente é melhor que a maioria dos algoritmos de pesquisa que você pode fazer.

Eu fiz da seguinte maneira. número e nome são dois arraylist. Eu tenho que classificar o nome. Se alguma mudança acontecer ao nomear a ordem arista, então o número arraylist também mudará sua ordem.

 public void sortval(){ String tempname="",tempnum=""; if (name.size()>1) // check if the number of orders is larger than 1 { for (int x=0; x 0) { tempname = name.get(i); tempnum=number.get(i); name.set(i,name.get(i+1) ); name.set(i+1, tempname); number.set(i,number.get(i+1) ); number.set(i+1, tempnum); } } } } } 

Você deve usar a function Arrays.sort. As classs que contêm devem implementar o Comparable.