Classificar um HashMap em Java

Classificar um HashMap em Java

1. Introdução

Neste tutorial rápido, aprenderemos comosort a HashMap in Java.

Mais especificamente, veremos como classificar entradas deHashMap por sua chave ou valor usando:

  • TreeMap

  • ArrayList eCollections.sort()

  • TreeSet

  • Usando a APIStream,e, finalmente,

  • Usando a bibliotecaGuava 

2. Usando umTreeMap

Como sabemos,keys in TreeMap are sorted using their natural order. Essa é uma boa solução quando queremos classificar os pares de valor-chave por sua chave. Portanto, a ideia é enviar todos os dados de nossoHashMap paraTreeMap.

Para começar, vamos definir umHashMape inicializá-lo com alguns dados:

Map map = new HashMap<>();

Employee employee1 = new Employee(1L, "Mher");
map.put(employee1.getName(), employee1);
Employee employee2 = new Employee(22L, "Annie");
map.put(employee2.getName(), employee2);
Employee employee3 = new Employee(8L, "John");
map.put(employee3.getName(), employee3);
Employee employee4 = new Employee(2L, "George");
map.put(employee4.getName(), employee4);

Para a classeEmployee,note that we’ve implemented Comparable:

public class Employee implements Comparable {

    private Long id;
    private String name;

    // constructor, getters, setters

    // override equals and hashCode
    @Override
    public int compareTo(Employee employee) {
        return (int)(this.id - employee.getId());
    }
}

Em seguida, armazenamos as entradas emTreeMap  usando seu construtor:

TreeMap sorted = new TreeMap<>(map);

Ou o métodoputAll para copiar os dados:

TreeMap sorted = new TreeMap<>();
sorted.putAll(map);

E é isso! Para garantir que nossas entradas de mapa sejam classificadas por chave, vamos imprimi-las:

Annie=Employee{id=22, name='Annie'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Mher=Employee{id=1, name='Mher'}

Como vemos, as chaves são classificadas em ordem natural.

3. UsandoArrayList

Claro, podemos classificar as entradas do mapa com a ajuda deArrayList. A principal diferença em relação ao método anterior é quewe don’t maintain the Map interface here.

3.1. Classificar por chave

Vamos carregar o conjunto de chaves em umArrayList:

List employeeByKey = new ArrayList<>(map.keySet());
Collections.sort(employeeByKey);

E a saída é:

[Annie, George, John, Mher]

3.2. Classificar por valor

Agora, e se quisermos classificar os valores do nosso mapa pelo campoid do objetoEmployee? Podemos usar umArrayList para isso também.

Primeiro, vamos copiar os valores para a lista:

List employeeById = new ArrayList<>(map.values());

E depois disso, nós classificamos:

Collections.sort(employeeById);

Lembre-se de que isso funciona porqueEmployee implements the Comparable interface. Caso contrário, precisaríamos definir um comparador manual para nossa chamada paraCollections.sort.

Para verificar os resultados, imprimimos oemployeeById:

[Employee{id=1, name='Mher'},
Employee{id=2, name='George'},
Employee{id=8, name='John'},
Employee{id=22, name='Annie'}]

Como vemos, os objetos são classificados por seus camposid.

4. Usando umTreeSet 

Caso nósdon’t want to accept duplicate values in our sorted collection, there is a nice solution with TreeSet.

Primeiro, vamos adicionar algumas entradas duplicadas ao nosso mapa inicial:

Employee employee5 = new Employee(1L, "Mher");
map.put(employee5.getName(), employee5);
Employee employee6 = new Employee(22L, "Annie");
map.put(employee6.getName(), employee6);

4.1. Classificar por chave

Para classificar o mapa por suas entradas principais:

SortedSet keySet = new TreeSet<>(map.keySet());

Vamos imprimir okeySete ver o resultado:

[Annie, George, John, Mher]

Agora, temos as chaves do mapa classificadas sem as duplicatas.

4.2. Classificar por valor

Da mesma forma, para os valores do mapa, o código de conversão se parece com:

SortedSet values = new TreeSet<>(map.values());

E os resultados são:

[Employee{id=1, name='Mher'},
Employee{id=2, name='George'},
Employee{id=8, name='John'},
Employee{id=22, name='Annie'}]

Como podemos ver, não há duplicatas na saída. This works with custom objects when we override equals and hashCode.

5. Usando Lambdas e Streams

Since the Java 8, we can use the Stream API and lambda expressions to sort the map. Tudo o que precisamos é chamar o métodosorted sobre a linha spipelinestream do mapa.

5.1. Classificar por chave

Para classificar por chave, usamos o scomparatorcomparingByKey :

map.entrySet()
  .stream()
  .sorted(Map.Entry.comparingByKey())
  .forEach(System.out::println);

O estágio finalforEach imprime os resultados:

Annie=Employee{id=22, name='Annie'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Mher=Employee{id=1, name='Mher'}

Por padrão, o modo de classificação está em ascensão.

5.2. Classificar por valor

Claro, podemos classificar pelos objetosEmployee também:

map.entrySet()
  .stream()
  .sorted(Map.Entry.comparingByValue())
  .forEach(System.out::println);

Como podemos ver, o código acima imprime um mapa classificado pelos camposid de objetosEmployee:

Mher=Employee{id=1, name='Mher'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Annie=Employee{id=22, name='Annie'}

Além disso, podemos coletar os resultados em um novo mapa:

Map result = map.entrySet()
  .stream()
  .sorted(Map.Entry.comparingByValue())
  .collect(Collectors.toMap(
    Map.Entry::getKey,
    Map.Entry::getValue,
    (oldValue, newValue) -> oldValue, LinkedHashMap::new));

Note that we collected our results into a LinkedHashMap. Por padrão,Collectors.toMap retorna um novo HashMap, mas como sabemos,HashMap doesn’t guarantee iterationorder, enquantoLinkedHashMap o faz.

6. Usando goiaba

Por último, uma biblioteca que nos permite ordenarHashMap é a Guava. Antes de começar, será útil verificar nosso artigo sobremaps in Guava.

Primeiro, vamos declarar umOrdering, pois queremos classificar nosso mapa pelo campoEmployee’sId:

Ordering naturalOrdering = Ordering.natural()
  .onResultOf(Functions.forMap(map, null));

Agora, tudo o que precisamos é usarImmutableSortedMap para ilustrar os resultados:

ImmutableSortedMap.copyOf(map, naturalOrdering);

E mais uma vez, a saída é um mapa ordenado pelo campoid:

Mher=Employee{id=1, name='Mher'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Annie=Employee{id=22, name='Annie'}

7. Sumário

Neste artigo, revisamos várias maneiras de classificar uma chaveHashMap by ou por valor.

E examinamos de perto como podemos fazer isso quando o atributo é uma classe personalizada, implementandoComparable.

Finalmente, como sempre, o código usado durante a discussão pode ser encontradoover on GitHub.