我对Java比较陌生,经常发现需要对值进行Map<Key,Value>排序。
由于这些值不是唯一的,我发现自己将keySet转换为一个数组,并使用自定义比较器通过数组排序对该数组进行排序,该比较器根据与该键关联的值进行排序。
有没有更简单的方法?
我对Java比较陌生,经常发现需要对值进行Map<Key,Value>排序。
由于这些值不是唯一的,我发现自己将keySet转换为一个数组,并使用自定义比较器通过数组排序对该数组进行排序,该比较器根据与该键关联的值进行排序。
有没有更简单的方法?
当前回答
从…起http://www.programmersheaven.com/download/49349/download.aspx
private static <K, V> Map<K, V> sortByValue(Map<K, V> map) {
List<Entry<K, V>> list = new LinkedList<>(map.entrySet());
Collections.sort(list, new Comparator<Object>() {
@SuppressWarnings("unchecked")
public int compare(Object o1, Object o2) {
return ((Comparable<V>) ((Map.Entry<K, V>) (o1)).getValue()).compareTo(((Map.Entry<K, V>) (o2)).getValue());
}
});
Map<K, V> result = new LinkedHashMap<>();
for (Iterator<Entry<K, V>> it = list.iterator(); it.hasNext();) {
Map.Entry<K, V> entry = (Map.Entry<K, V>) it.next();
result.put(entry.getKey(), entry.getValue());
}
return result;
}
其他回答
我重写了devinmore的方法,该方法在不使用迭代器的情况下,根据地图的值对其进行排序:
public static Map<K, V> sortMapByValue(Map<K, V> inputMap) {
Set<Entry<K, V>> set = inputMap.entrySet();
List<Entry<K, V>> list = new ArrayList<Entry<K, V>>(set);
Collections.sort(list, new Comparator<Map.Entry<K, V>>()
{
@Override
public int compare(Entry<K, V> o1, Entry<K, V> o2) {
return (o1.getValue()).compareTo( o2.getValue() ); //Ascending order
}
} );
Map<K, V> sortedMap = new LinkedHashMap<>();
for(Map.Entry<K, V> entry : list){
sortedMap.put(entry.getKey(), entry.getValue());
}
return sortedMap;
}
注意:我们使用LinkedHashMap作为输出映射,因为我们的列表已经按值排序,现在我们应该按照插入键值的顺序将列表存储到输出映射中。因此,如果您使用例如TreeMap作为输出地图,您的地图将再次按地图键排序!
这是主要方法:
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("3", "three");
map.put("1", "one");
map.put("5", "five");
System.out.println("Input Map:" + map);
System.out.println("Sorted Map:" + sortMapByValue(map));
}
最后,这是输出:
Input Map:{1=one, 3=three, 5=five}
Sorted Map:{5=five, 1=one, 3=three}
我的解决方案是一种非常简单的方法,使用大多数给定的API。我们使用Map的特性通过entrySet()方法将其内容导出为Set。我们现在有一个包含Map.Entry对象的集合。
好的,集合不携带订单,但我们可以将内容放入ArrayList。它现在有一个随机顺序,但无论如何我们都会对它进行排序。
由于ArrayList是一个集合,所以我们现在使用Collections.sort()方法来将秩序带入混乱。因为我们的Map.Entry对象没有实现我们需要的那种比较,所以我们提供了一个自定义比较器。
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<>();
map.put("Z", "E");
map.put("G", "A");
map.put("D", "C");
map.put("E", null);
map.put("O", "C");
map.put("L", "D");
map.put("Q", "B");
map.put("A", "F");
map.put(null, "X");
MapEntryComparator mapEntryComparator = new MapEntryComparator();
List<Entry<String,String>> entryList = new ArrayList<>(map.entrySet());
Collections.sort(entryList, mapEntryComparator);
for (Entry<String, String> entry : entryList) {
System.out.println(entry.getKey() + " : " + entry.getValue());
}
}
基于@devinmore代码,一种使用泛型并支持升序和降序排序的map排序方法。
/**
* Sort a map by it's keys in ascending order.
*
* @return new instance of {@link LinkedHashMap} contained sorted entries of supplied map.
* @author Maxim Veksler
*/
public static <K, V> LinkedHashMap<K, V> sortMapByKey(final Map<K, V> map) {
return sortMapByKey(map, SortingOrder.ASCENDING);
}
/**
* Sort a map by it's values in ascending order.
*
* @return new instance of {@link LinkedHashMap} contained sorted entries of supplied map.
* @author Maxim Veksler
*/
public static <K, V> LinkedHashMap<K, V> sortMapByValue(final Map<K, V> map) {
return sortMapByValue(map, SortingOrder.ASCENDING);
}
/**
* Sort a map by it's keys.
*
* @param sortingOrder {@link SortingOrder} enum specifying requested sorting order.
* @return new instance of {@link LinkedHashMap} contained sorted entries of supplied map.
* @author Maxim Veksler
*/
public static <K, V> LinkedHashMap<K, V> sortMapByKey(final Map<K, V> map, final SortingOrder sortingOrder) {
Comparator<Map.Entry<K, V>> comparator = new Comparator<Entry<K,V>>() {
public int compare(Entry<K, V> o1, Entry<K, V> o2) {
return comparableCompare(o1.getKey(), o2.getKey(), sortingOrder);
}
};
return sortMap(map, comparator);
}
/**
* Sort a map by it's values.
*
* @param sortingOrder {@link SortingOrder} enum specifying requested sorting order.
* @return new instance of {@link LinkedHashMap} contained sorted entries of supplied map.
* @author Maxim Veksler
*/
public static <K, V> LinkedHashMap<K, V> sortMapByValue(final Map<K, V> map, final SortingOrder sortingOrder) {
Comparator<Map.Entry<K, V>> comparator = new Comparator<Entry<K,V>>() {
public int compare(Entry<K, V> o1, Entry<K, V> o2) {
return comparableCompare(o1.getValue(), o2.getValue(), sortingOrder);
}
};
return sortMap(map, comparator);
}
@SuppressWarnings("unchecked")
private static <T> int comparableCompare(T o1, T o2, SortingOrder sortingOrder) {
int compare = ((Comparable<T>)o1).compareTo(o2);
switch (sortingOrder) {
case ASCENDING:
return compare;
case DESCENDING:
return (-1) * compare;
}
return 0;
}
/**
* Sort a map by supplied comparator logic.
*
* @return new instance of {@link LinkedHashMap} contained sorted entries of supplied map.
* @author Maxim Veksler
*/
public static <K, V> LinkedHashMap<K, V> sortMap(final Map<K, V> map, final Comparator<Map.Entry<K, V>> comparator) {
// Convert the map into a list of key,value pairs.
List<Map.Entry<K, V>> mapEntries = new LinkedList<Map.Entry<K, V>>(map.entrySet());
// Sort the converted list according to supplied comparator.
Collections.sort(mapEntries, comparator);
// Build a new ordered map, containing the same entries as the old map.
LinkedHashMap<K, V> result = new LinkedHashMap<K, V>(map.size() + (map.size() / 20));
for(Map.Entry<K, V> entry : mapEntries) {
// We iterate on the mapEntries list which is sorted by the comparator putting new entries into
// the targeted result which is a sorted map.
result.put(entry.getKey(), entry.getValue());
}
return result;
}
/**
* Sorting order enum, specifying request result sort behavior.
* @author Maxim Veksler
*
*/
public static enum SortingOrder {
/**
* Resulting sort will be from smaller to biggest.
*/
ASCENDING,
/**
* Resulting sort will be from biggest to smallest.
*/
DESCENDING
}
您可以尝试Guava的多功能地图:
TreeMap<Integer, Collection<String>> sortedMap = new TreeMap<>(
Multimaps.invertFrom(Multimaps.forMap(originalMap),
ArrayListMultimap.<Integer, String>create()).asMap());
因此,您将获得从原始值到对应于它们的键集合的映射。即使同一值有多个键,也可以使用此方法。
我合并了user157196和Carter Page的解决方案:
class MapUtil {
public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue( Map<K, V> map ){
ValueComparator<K,V> bvc = new ValueComparator<K,V>(map);
TreeMap<K,V> sorted_map = new TreeMap<K,V>(bvc);
sorted_map.putAll(map);
return sorted_map;
}
}
class ValueComparator<K, V extends Comparable<? super V>> implements Comparator<K> {
Map<K, V> base;
public ValueComparator(Map<K, V> base) {
this.base = base;
}
public int compare(K a, K b) {
int result = (base.get(a).compareTo(base.get(b)));
if (result == 0) result=1;
// returning 0 would merge keys
return result;
}
}