Je dois trier ma HashMap
en fonction des valeurs qui y sont stockées. La HashMap
contient le nom des contacts enregistrés dans le téléphone.
De plus, j'ai besoin que les clés soient automatiquement triées dès que je trie les valeurs, ou vous pouvez dire que les clés et les valeurs sont liées, de sorte que toute modification des valeurs doit être reflétée dans les clés.
HashMap<Integer,String> map = new HashMap<Integer,String>();
map.put(1,"froyo");
map.put(2,"abby");
map.put(3,"denver");
map.put(4,"frost");
map.put(5,"daisy");
Sortie requise:
2,abby;
5,daisy;
3,denver;
4,frost;
1,froyo;
En supposant que Java, vous pouvez trier hashmap juste comme ceci:
public LinkedHashMap<Integer, String> sortHashMapByValues(
HashMap<Integer, String> passedMap) {
List<Integer> mapKeys = new ArrayList<>(passedMap.keySet());
List<String> mapValues = new ArrayList<>(passedMap.values());
Collections.sort(mapValues);
Collections.sort(mapKeys);
LinkedHashMap<Integer, String> sortedMap =
new LinkedHashMap<>();
Iterator<String> valueIt = mapValues.iterator();
while (valueIt.hasNext()) {
String val = valueIt.next();
Iterator<Integer> keyIt = mapKeys.iterator();
while (keyIt.hasNext()) {
Integer key = keyIt.next();
String comp1 = passedMap.get(key);
String comp2 = val;
if (comp1.equals(comp2)) {
keyIt.remove();
sortedMap.put(key, val);
break;
}
}
}
return sortedMap;
}
Juste un exemple de coup d'envoi. Cette méthode est plus utile car elle trie le HashMap et conserve les valeurs en double.
Essayez ci-dessous le code cela fonctionne très bien pour moi. Vous pouvez choisir l'ordre croissant ou décroissant
import Java.util.Collections;
import Java.util.Comparator;
import Java.util.HashMap;
import Java.util.LinkedHashMap;
import Java.util.LinkedList;
import Java.util.List;
import Java.util.Map;
import Java.util.Map.Entry;
public class SortMapByValue
{
public static boolean ASC = true;
public static boolean DESC = false;
public static void main(String[] args)
{
// Creating dummy unsorted map
Map<String, Integer> unsortMap = new HashMap<String, Integer>();
unsortMap.put("B", 55);
unsortMap.put("A", 80);
unsortMap.put("D", 20);
unsortMap.put("C", 70);
System.out.println("Before sorting......");
printMap(unsortMap);
System.out.println("After sorting ascending order......");
Map<String, Integer> sortedMapAsc = sortByComparator(unsortMap, ASC);
printMap(sortedMapAsc);
System.out.println("After sorting descindeng order......");
Map<String, Integer> sortedMapDesc = sortByComparator(unsortMap, DESC);
printMap(sortedMapDesc);
}
private static Map<String, Integer> sortByComparator(Map<String, Integer> unsortMap, final boolean order)
{
List<Entry<String, Integer>> list = new LinkedList<Entry<String, Integer>>(unsortMap.entrySet());
// Sorting the list based on values
Collections.sort(list, new Comparator<Entry<String, Integer>>()
{
public int compare(Entry<String, Integer> o1,
Entry<String, Integer> o2)
{
if (order)
{
return o1.getValue().compareTo(o2.getValue());
}
else
{
return o2.getValue().compareTo(o1.getValue());
}
}
});
// Maintaining insertion order with the help of LinkedList
Map<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();
for (Entry<String, Integer> entry : list)
{
sortedMap.put(entry.getKey(), entry.getValue());
}
return sortedMap;
}
public static void printMap(Map<String, Integer> map)
{
for (Entry<String, Integer> entry : map.entrySet())
{
System.out.println("Key : " + entry.getKey() + " Value : "+ entry.getValue());
}
}
}
Edit: Version 2
Utilisé une nouvelle fonctionnalité Java comme stream for-each etc
La carte sera triée par clés si les valeurs sont identiques
import Java.util.*;
import Java.util.Map.Entry;
import Java.util.stream.Collectors;
public class SortMapByValue
{
private static boolean ASC = true;
private static boolean DESC = false;
public static void main(String[] args)
{
// Creating dummy unsorted map
Map<String, Integer> unsortMap = new HashMap<>();
unsortMap.put("B", 55);
unsortMap.put("A", 20);
unsortMap.put("D", 20);
unsortMap.put("C", 70);
System.out.println("Before sorting......");
printMap(unsortMap);
System.out.println("After sorting ascending order......");
Map<String, Integer> sortedMapAsc = sortByValue(unsortMap, ASC);
printMap(sortedMapAsc);
System.out.println("After sorting descending order......");
Map<String, Integer> sortedMapDesc = sortByValue(unsortMap, DESC);
printMap(sortedMapDesc);
}
private static Map<String, Integer> sortByValue(Map<String, Integer> unsortMap, final boolean order)
{
List<Entry<String, Integer>> list = new LinkedList<>(unsortMap.entrySet());
// Sorting the list based on values
list.sort((o1, o2) -> order ? o1.getValue().compareTo(o2.getValue()) == 0
? o1.getKey().compareTo(o2.getKey())
: o1.getValue().compareTo(o2.getValue()) : o2.getValue().compareTo(o1.getValue()) == 0
? o2.getKey().compareTo(o1.getKey())
: o2.getValue().compareTo(o1.getValue()));
return list.stream().collect(Collectors.toMap(Entry::getKey, Entry::getValue, (a, b) -> b, LinkedHashMap::new));
}
private static void printMap(Map<String, Integer> map)
{
map.forEach((key, value) -> System.out.println("Key : " + key + " Value : " + value));
}
}
En Java 8:
Map<Integer, String> sortedMap =
unsortedMap.entrySet().stream()
.sorted(Entry.comparingByValue())
.collect(Collectors.toMap(Entry::getKey, Entry::getValue,
(e1, e2) -> e1, LinkedHashMap::new));
Vous n'avez pas, fondamentalement. Une HashMap
est fondamentalement non ordonnée. Tous les modèles que vous pourriez voir dans l'ordre devraient être utilisés pas.
Il existe des cartes triées telles que TreeMap
, mais elles sont classées par clé plutôt que par valeur. Il est relativement inhabituel de trier par valeur - d'autant plus que plusieurs clés peuvent avoir la même valeur.
Pouvez-vous donner plus de contexte à ce que vous essayez de faire? Si vous ne stockez que des nombres (sous forme de chaînes) pour les clés, une SortedSet
telle que TreeSet
fonctionnerait-elle pour vous?
Sinon, vous pouvez stocker deux collections distinctes encapsulées dans une même classe pour les mettre à jour simultanément?
package com.naveen.hashmap;
import Java.util.*;
import Java.util.Map.Entry;
public class SortBasedonValues {
/**
* @param args
*/
public static void main(String[] args) {
HashMap<String, Integer> hm = new HashMap<String, Integer>();
hm.put("Naveen", 2);
hm.put("Santosh", 3);
hm.put("Ravi", 4);
hm.put("Pramod", 1);
Set<Entry<String, Integer>> set = hm.entrySet();
List<Entry<String, Integer>> list = new ArrayList<Entry<String, Integer>>(
set);
Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
public int compare(Map.Entry<String, Integer> o1,
Map.Entry<String, Integer> o2) {
return o2.getValue().compareTo(o1.getValue());
}
});
for (Entry<String, Integer> entry : list) {
System.out.println(entry.getValue());
}
}
}
map.entrySet().stream()
.sorted((k1, k2) -> -k1.getValue().compareTo(k2.getValue()))
.forEach(k -> System.out.println(k.getKey() + ": " + k.getValue()));
En guise de solution simple, vous pouvez utiliser TreeMap temporaire si vous souhaitez obtenir un résultat final:
TreeMap<String, Integer> sortedMap = new TreeMap<String, Integer>();
for (Map.Entry entry : map.entrySet()) {
sortedMap.put((String) entry.getValue(), (Integer)entry.getKey());
}
Cela vous permettra de trier les chaînes en tant que clés de triMap.
J'étend un TreeMap et substitue les méthodes entrySet () et values (). La clé et la valeur doivent être comparables.
Suivez le code:
public class ValueSortedMap<K extends Comparable, V extends Comparable> extends TreeMap<K, V> {
@Override
public Set<Entry<K, V>> entrySet() {
Set<Entry<K, V>> originalEntries = super.entrySet();
Set<Entry<K, V>> sortedEntry = new TreeSet<Entry<K, V>>(new Comparator<Entry<K, V>>() {
@Override
public int compare(Entry<K, V> entryA, Entry<K, V> entryB) {
int compareTo = entryA.getValue().compareTo(entryB.getValue());
if(compareTo == 0) {
compareTo = entryA.getKey().compareTo(entryB.getKey());
}
return compareTo;
}
});
sortedEntry.addAll(originalEntries);
return sortedEntry;
}
@Override
public Collection<V> values() {
Set<V> sortedValues = new TreeSet<>(new Comparator<V>(){
@Override
public int compare(V vA, V vB) {
return vA.compareTo(vB);
}
});
sortedValues.addAll(super.values());
return sortedValues;
}
}
Tests unitaires:
public class ValueSortedMapTest {
@Test
public void basicTest() {
Map<String, Integer> sortedMap = new ValueSortedMap<>();
sortedMap.put("A",3);
sortedMap.put("B",1);
sortedMap.put("C",2);
Assert.assertEquals("{B=1, C=2, A=3}", sortedMap.toString());
}
@Test
public void repeatedValues() {
Map<String, Double> sortedMap = new ValueSortedMap<>();
sortedMap.put("D",67.3);
sortedMap.put("A",99.5);
sortedMap.put("B",67.4);
sortedMap.put("C",67.4);
Assert.assertEquals("{D=67.3, B=67.4, C=67.4, A=99.5}", sortedMap.toString());
}
}
trouvé une solution, mais pas sûr que les performances si la carte a une grande taille, utile pour les cas normaux.
/**
* sort HashMap<String, CustomData> by value
* CustomData needs to provide compareTo() for comparing CustomData
* @param map
*/
public void sortHashMapByValue(final HashMap<String, CustomData> map) {
ArrayList<String> keys = new ArrayList<String>();
keys.addAll(map.keySet());
Collections.sort(keys, new Comparator<String>() {
@Override
public int compare(String lhs, String rhs) {
CustomData val1 = map.get(lhs);
CustomData val2 = map.get(rhs);
if (val1 == null) {
return (val2 != null) ? 1 : 0;
} else if (val1 != null) && (val2 != null)) {
return = val1.compareTo(val2);
}
else {
return 0;
}
}
});
for (String key : keys) {
CustomData c = map.get(key);
if (c != null) {
Log.e("key:"+key+", CustomData:"+c.toString());
}
}
}
package SortedSet;
import Java.util.*;
public class HashMapValueSort {
public static void main(String[] args){
final Map<Integer, String> map = new HashMap<Integer,String>();
map.put(4,"Mango");
map.put(3,"Apple");
map.put(5,"Orange");
map.put(8,"Fruits");
map.put(23,"Vegetables");
map.put(1,"Zebra");
map.put(5,"Yellow");
System.out.println(map);
final HashMapValueSort sort = new HashMapValueSort();
final Set<Map.Entry<Integer, String>> entry = map.entrySet();
final Comparator<Map.Entry<Integer, String>> comparator = new Comparator<Map.Entry<Integer, String>>() {
@Override
public int compare(Map.Entry<Integer, String> o1, Map.Entry<Integer, String> o2) {
String value1 = o1.getValue();
String value2 = o2.getValue();
return value1.compareTo(value2);
}
};
final SortedSet<Map.Entry<Integer, String>> sortedSet = new TreeSet(comparator);
sortedSet.addAll(entry);
final Map<Integer,String> sortedMap = new LinkedHashMap<Integer, String>();
for(Map.Entry<Integer, String> entry1 : sortedSet ){
sortedMap.put(entry1.getKey(),entry1.getValue());
}
System.out.println(sortedMap);
}
}