Categorías
Collections Java

Java – Ordenar mapa por valor

En Java, podemos usar el TreeMap class para ordenar un mapa por sus claves. Esta clase es muy útil de usar. Sin embargo, a veces necesitamos ordenar un mapa por sus valores. Cómo ordenar un mapa por sus valores es una de las preguntas más frecuentes de los programadores de Java. En esta publicación, desarrollaré la mejor manera de escribir dicho método.

1. Método ingenuo

La siguiente es una solución para ordenar un mapa de pares . Esto se usa a menudo para contar la frecuencia de las palabras.

import java.util.Comparator;
import java.util.HashMap;
import java.util.TreeMap;
 
public class SortMapByValue {
 
	public static void main(String[] args) {
		HashMap<String, Integer> map = new HashMap<String, Integer>();
		map.put("a", 10);
		map.put("b", 30);
		map.put("c", 50);
		map.put("d", 40);
		map.put("e", 20);
		System.out.println(map);
 
		TreeMap<String, Integer> sortedMap = sortMapByValue(map);  
		System.out.println(sortedMap);
	}
 
	public static TreeMap<String, Integer> sortMapByValue(HashMap<String, Integer> map){
		Comparator<String> comparator = new ValueComparator(map);
		//TreeMap is a map sorted by its keys. 
		//The comparator is used to sort the TreeMap by keys. 
		TreeMap<String, Integer> result = new TreeMap<String, Integer>(comparator);
		result.putAll(map);
		return result;
	}
}

Aquí está la implementación de la clase de comparador.

// a comparator that compares Strings
class ValueComparator implements Comparator<String>{
 
	HashMap<String, Integer> map = new HashMap<String, Integer>();
 
	public ValueComparator(HashMap<String, Integer> map){
		this.map.putAll(map);
	}
 
	@Override
	public int compare(String s1, String s2) {
		if(map.get(s1) >= map.get(s2)){
			return -1;
		}else{
			return 1;
		}	
	}
}
  ¿Cómo se imprime “Hello World”? - Un ciclo de vida completo

En esta solución, usamos un TreeMap para ordenar el mapa. Al crear el TreeMap, le damos un comparador. El comparador acepta cadenas y compara los valores asociados de la clave de cadena dada en el mapa.

El método funciona bien, pero solo funciona para ordenar pares de cadenas y enteros. Si queremos ordenar un mapa con otros tipos de claves y valores, es necesario reescribirlo. Por tanto, se prefiere una solución más general.

2. Solución más general

Podemos ignorar el tipo genérico y hacer que los métodos funcionen para cualquier tipo como el siguiente.

import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
 
public class Solution {
	public static void main(String[] args) {
		HashMap<String, Integer> map = new HashMap<String, Integer>();
		map.put("a", 10);
		map.put("b", 30);
		map.put("c", 50);
		map.put("d", 40);
		map.put("e", 20);
		System.out.println(map);
 
		Map sortedMap = sortByValue(map);
		System.out.println(sortedMap);
	}
 
	public static Map sortByValue(Map unsortedMap) {
		Map sortedMap = new TreeMap(new ValueComparator(unsortedMap));
		sortedMap.putAll(unsortedMap);
		return sortedMap;
	}
 
}
 
class ValueComparator implements Comparator {
	Map map;
 
	public ValueComparator(Map map) {
		this.map = map;
	}
 
	public int compare(Object keyA, Object keyB) {
		Comparable valueA = (Comparable) map.get(keyA);
		Comparable valueB = (Comparable) map.get(keyB);
		return valueB.compareTo(valueA);
	}
}
  ArrayList frente a LinkedList frente a vector

La solución no es de tipo seguro, necesitamos una solución general y de tipo seguro.

3. Uso de tipos genéricos

public class SortMapByValue {
 
	public static void main(String[] args) {
		// <String, Integer> Map
		HashMap<String, Integer> map = new HashMap<String, Integer>();
		map.put("a", 10);
		map.put("b", 30);
		map.put("c", 50);
		map.put("d", 40);
		map.put("e", 20);
		System.out.println(map);
 
 
		Comparator<String> comparator = new ValueComparator<String, Integer>(map);
		TreeMap<String, Integer> result = new TreeMap<String, Integer>(comparator);
		result.putAll(map);
 
		System.out.println(result);
 
		// <Integer, Integer> Map
 
		HashMap<Integer, Integer> map2 = new HashMap<Integer, Integer>();
		map2.put(1, 10);
		map2.put(2, 30);
		map2.put(3, 50);
		map2.put(4, 40);
		map2.put(5, 20);
		System.out.println(map2);
 
		Comparator<Integer> comparator2 = new ValueComparator<Integer, Integer>(map2);
		TreeMap<Integer, Integer> result2 = new TreeMap<Integer, Integer>(comparator2);
		result2.putAll(map2);
 
		System.out.println(result2);
 
	}
 
}
// a comparator using generic type
class ValueComparator<K, V extends Comparable<V>> implements Comparator<K>{
 
	HashMap<K, V> map = new HashMap<K, V>();
 
	public ValueComparator(HashMap<K, V> map){
		this.map.putAll(map);
	}
 
	@Override
	public int compare(K s1, K s2) {
		return -map.get(s1).compareTo(map.get(s2));//descending order	
	}
}
  Ejemplos de enumeración de Java

4. Otra forma de utilizar tipos genéricos

public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) {
	List<Map.Entry<K, V>> list = new LinkedList<>(map.entrySet());
	Collections.sort(list, new Comparator<Map.Entry<K, V>>() {
		@Override
		public int compare(Map.Entry<K, V> e1, Map.Entry<K, V> e2) {
			return (e1.getValue()).compareTo(e2.getValue());
		}
	});
 
	Map<K, V> result = new LinkedHashMap<>();
	for (Map.Entry<K, V> entry : list) {
		result.put(entry.getKey(), entry.getValue());
	}
 
	return result;
}

5. Simple

Cuando necesite una solución simple, la clasificación se puede hacer en una línea.

LinkedList<Map.Entry<String, Integer>> list = new LinkedList<>(counter.entrySet());
Comparator<Map.Entry<String, Integer>> comparator = Comparator.comparing(Map.Entry::getValue);
Collections.sort(list, comparator.reversed());

Por Programación.Click

Más de 20 años programando en diferentes lenguajes de programación. Apasionado del code clean y el terminar lo que se empieza. ¿Programamos de verdad?

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *