按值对 HashMap 排序

我需要根据 HashMap中存储的值对它进行排序。HashMap包含存储在手机中的联系人名称。

另外,我需要的键自动排序,只要我排序的值,或者你可以说键和值绑定在一起,因此任何变化的值应该反映在键。

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");

所需产出:

2,abby;
5,daisy;
3,denver;
4,frost;
1,froyo;
516478 次浏览

基本上你不知道。HashMap基本上是无序的。也许吧在排序中看到的任何模式都应该依赖于 没有

有像 TreeMap这样的排序映射,但是它们传统上是按键排序而不是按值排序。通过值进行排序是相对不寻常的——特别是多个键可以具有相同的值。

你能给出更多的背景知识来说明你正在尝试做的事情吗?如果您实际上只是为键存储数字(作为字符串) ,那么 SortedSet(如 TreeSet)可能对您有用?

或者,您可以存储封装在单个类中的两个单独的集合,以便同时更新这两个集合?

假设使用 Java,您可以像下面这样对散列表进行排序:

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

只是个开始的例子。这种方法更有用,因为它对 HashMap 进行排序,并保留重复的值。

Map进行排序的方法的通用版本类似于:

private static <K extends Comparable<K>, V extends Comparable<V>> Map<K, V> sort(
final Map<K, V> unsorted,
final boolean order) {
final var list = new LinkedList<>(unsorted.entrySet());


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

下面的代码提供了按值升序和降序排序:

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 final boolean ASC = true;
public static final 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());
}
}
}

使用新的 Java 特性:

 import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
    

public class SortMapByValue


{
private static final boolean ASC = true;
private static final 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));
}
}
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);
}
}
public static TreeMap<String, String> sortMap(HashMap<String, String> passedMap, String byParam) {
if(byParam.trim().toLowerCase().equalsIgnoreCase("byValue")) {
// Altering the (key, value) -> (value, key)
HashMap<String, String> newMap =  new HashMap<String, String>();
for (Map.Entry<String, String> entry : passedMap.entrySet()) {
newMap.put(entry.getValue(), entry.getKey());
}
return new TreeMap<String, String>(newMap);
}
return new TreeMap<String, String>(passedMap);
}

在 Java 8中:

Map<Integer, String> sortedMap =
unsortedMap.entrySet().stream()
.sorted(Entry.comparingByValue())
.collect(Collectors.toMap(Entry::getKey, Entry::getValue,
(e1, e2) -> e1, LinkedHashMap::new));
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;


public class CollectionsSort {


/**
* @param args
*/`enter code here`
public static void main(String[] args) {
// TODO Auto-generated method stub


CollectionsSort colleciotns = new CollectionsSort();


List<combine> list = new ArrayList<combine>();
HashMap<String, Integer> h = new HashMap<String, Integer>();
h.put("nayanana", 10);
h.put("lohith", 5);


for (Entry<String, Integer> value : h.entrySet()) {
combine a = colleciotns.new combine(value.getValue(),
value.getKey());
list.add(a);
}


Collections.sort(list);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}


public class combine implements Comparable<combine> {


public int value;
public String key;


public combine(int value, String key) {
this.value = value;
this.key = key;
}


@Override
public int compareTo(combine arg0) {
// TODO Auto-generated method stub
return this.value > arg0.value ? 1 : this.value < arg0.value ? -1
: 0;
}


public String toString() {
return this.value + " " + this.key;
}
}


}

找到了一个解决方案,但不确定性能,如果地图有大尺寸,有用的正常情况下。

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

作为一种简单的解决方案,如果只需要最终结果,可以使用 temp TreeMap:

TreeMap<String, Integer> sortedMap = new TreeMap<String, Integer>();
for (Map.Entry entry : map.entrySet()) {
sortedMap.put((String) entry.getValue(), (Integer)entry.getKey());
}

这将使字符串作为 sortedMap 的键进行排序。

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

我扩展了 TreeMap 并覆盖 entrySet ()和 values ()方法。

遵循代码:

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

单元测试:

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


}