我对Java比较陌生,经常发现需要对值进行Map<Key,Value>排序。
由于这些值不是唯一的,我发现自己将keySet转换为一个数组,并使用自定义比较器通过数组排序对该数组进行排序,该比较器根据与该键关联的值进行排序。
有没有更简单的方法?
我对Java比较陌生,经常发现需要对值进行Map<Key,Value>排序。
由于这些值不是唯一的,我发现自己将keySet转换为一个数组,并使用自定义比较器通过数组排序对该数组进行排序,该比较器根据与该键关联的值进行排序。
有没有更简单的方法?
当前回答
commons集合库包含一个名为TreeBidiMap的解决方案。或者,你可以看看谷歌收藏API。它有你可以使用的TreeMultimap。
如果你不想使用这些框架。。。它们带有源代码。
其他回答
因为地图是无序的要对其进行排序,我们可以执行以下操作
Map<String, String> map= new TreeMap<String, String>(unsortMap);
您应该注意,与哈希映射不同,树映射保证其元素将按升序键排序。
Java 8提供了一个新的答案:将条目转换为流,并使用Map中的比较器组合符。条目:
Stream<Map.Entry<K,V>> sorted =
map.entrySet().stream()
.sorted(Map.Entry.comparingByValue());
这将允许您使用按值升序排序的条目。如果您想要递减值,只需反转比较器:
Stream<Map.Entry<K,V>> sorted =
map.entrySet().stream()
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()));
如果这些值不可比较,则可以传递显式比较器:
Stream<Map.Entry<K,V>> sorted =
map.entrySet().stream()
.sorted(Map.Entry.comparingByValue(comparator));
然后,您可以继续使用其他流操作来使用数据。例如,如果要在新地图中显示前10名:
Map<K,V> topTen =
map.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.limit(10)
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
上面看到的LinkedHashMap按插入顺序迭代条目。
或打印到System.out:
map.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
.forEach(System.out::println);
重要说明:
此代码可以以多种方式中断。如果您打算使用提供的代码,请务必阅读注释以了解其含义。例如,值不能再通过其键检索。(get始终返回null。)
这似乎比前面所有的都容易得多。按如下方式使用TreeMap:
public class Testing {
public static void main(String[] args) {
HashMap<String, Double> map = new HashMap<String, Double>();
ValueComparator bvc = new ValueComparator(map);
TreeMap<String, Double> sorted_map = new TreeMap<String, Double>(bvc);
map.put("A", 99.5);
map.put("B", 67.4);
map.put("C", 67.4);
map.put("D", 67.3);
System.out.println("unsorted map: " + map);
sorted_map.putAll(map);
System.out.println("results: " + sorted_map);
}
}
class ValueComparator implements Comparator<String> {
Map<String, Double> base;
public ValueComparator(Map<String, Double> base) {
this.base = base;
}
// Note: this comparator imposes orderings that are inconsistent with
// equals.
public int compare(String a, String b) {
if (base.get(a) >= base.get(b)) {
return -1;
} else {
return 1;
} // returning 0 would merge keys
}
}
输出:
unsorted map: {D=67.3, A=99.5, B=67.4, C=67.4}
results: {D=67.3, B=67.4, C=67.4, A=99.5}
map = your hashmap;
List<Map.Entry<String, Integer>> list = new LinkedList<Map.Entry<String, Integer>>(map.entrySet());
Collections.sort(list, new cm());//IMP
HashMap<String, Integer> sorted = new LinkedHashMap<String, Integer>();
for(Map.Entry<String, Integer> en: list){
sorted.put(en.getKey(),en.getValue());
}
System.out.println(sorted);//sorted hashmap
创建新类
class cm implements Comparator<Map.Entry<String, Integer>>{
@Override
public int compare(Map.Entry<String, Integer> a,
Map.Entry<String, Integer> b)
{
return (a.getValue()).compareTo(b.getValue());
}
}
这太复杂了。地图不应该按价值排序。最简单的方法是创建自己的类,以满足您的需求。
在下面的示例中,您应该在*所在的位置添加TreeMap比较器。但通过javaAPI,它只提供比较器键,而不提供值。此处所述的所有示例均基于2个地图。一个哈希和一个新树。这很奇怪。
示例:
Map<Driver driver, Float time> map = new TreeMap<Driver driver, Float time>(*);
因此,通过以下方式将地图更改为集合:
ResultComparator rc = new ResultComparator();
Set<Results> set = new TreeSet<Results>(rc);
您将创建类Results,
public class Results {
private Driver driver;
private Float time;
public Results(Driver driver, Float time) {
this.driver = driver;
this.time = time;
}
public Float getTime() {
return time;
}
public void setTime(Float time) {
this.time = time;
}
public Driver getDriver() {
return driver;
}
public void setDriver (Driver driver) {
this.driver = driver;
}
}
以及Comparator类:
public class ResultsComparator implements Comparator<Results> {
public int compare(Results t, Results t1) {
if (t.getTime() < t1.getTime()) {
return 1;
} else if (t.getTime() == t1.getTime()) {
return 0;
} else {
return -1;
}
}
}
这样,您可以轻松添加更多依赖项。
最后一点,我将添加简单迭代器:
Iterator it = set.iterator();
while (it.hasNext()) {
Results r = (Results)it.next();
System.out.println( r.getDriver().toString
//or whatever that is related to Driver class -getName() getSurname()
+ " "
+ r.getTime()
);
}