public int compare(String a, String b) {
if (base.get(a) > base.get(b)) {
return 1;
} else if (base.get(a) < base.get(b)){
return -1;
}
return 0;
// returning 0 would merge keys
}
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;
}
}
和比较者类:
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()
);
}
public class MapUtilities {
public static <K, V extends Comparable<V>> List<Entry<K, V>> sortByValue(Map<K, V> map) {
List<Entry<K, V>> entries = new ArrayList<Entry<K, V>>(map.entrySet());
Collections.sort(entries, new ByValue<K, V>());
return entries;
}
private static class ByValue<K, V extends Comparable<V>> implements Comparator<Entry<K, V>> {
public int compare(Entry<K, V> o1, Entry<K, V> o2) {
return o1.getValue().compareTo(o2.getValue());
}
}
}
这是一个令人尴尬的不完整的单元测试:
public class MapUtilitiesTest extends TestCase {
public void testSorting() {
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("One", 1);
map.put("Two", 2);
map.put("Three", 3);
List<Map.Entry<String, Integer>> sorted = MapUtilities.sortByValue(map);
assertEquals("First", "One", sorted.get(0).getKey());
assertEquals("Second", "Two", sorted.get(1).getKey());
assertEquals("Third", "Three", sorted.get(2).getKey());
}
}
结果是Map.Entry对象的排序列表,您可以从中获取键和值 .
11
我已经合并了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;
}
}
import java.util.*;
/**
* A map where {@link #keySet()} and {@link #entrySet()} return sets ordered
* by associated values based on the the comparator provided at construction
* time. The order of two or more keys with identical values is not defined.
* <p>
* Several contracts of the Map interface are not satisfied by this minimal
* implementation.
*/
public class ValueSortedMap<K, V> extends HashMap<K, V> {
protected Map<V, Collection<K>> valueToKeysMap;
// uses natural order of value object, if any
public ValueSortedMap() {
this((Comparator<? super V>) null);
}
public ValueSortedMap(Comparator<? super V> valueComparator) {
this.valueToKeysMap = new TreeMap<V, Collection<K>>(valueComparator);
}
public boolean containsValue(Object o) {
return valueToKeysMap.containsKey(o);
}
public V put(K k, V v) {
V oldV = null;
if (containsKey(k)) {
oldV = get(k);
valueToKeysMap.get(oldV).remove(k);
}
super.put(k, v);
if (!valueToKeysMap.containsKey(v)) {
Collection<K> keys = new ArrayList<K>();
keys.add(k);
valueToKeysMap.put(v, keys);
} else {
valueToKeysMap.get(v).add(k);
}
return oldV;
}
public void putAll(Map<? extends K, ? extends V> m) {
for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
put(e.getKey(), e.getValue());
}
public V remove(Object k) {
V oldV = null;
if (containsKey(k)) {
oldV = get(k);
super.remove(k);
valueToKeysMap.get(oldV).remove(k);
}
return oldV;
}
public void clear() {
super.clear();
valueToKeysMap.clear();
}
public Set<K> keySet() {
LinkedHashSet<K> ret = new LinkedHashSet<K>(size());
for (V v : valueToKeysMap.keySet()) {
Collection<K> keys = valueToKeysMap.get(v);
ret.addAll(keys);
}
return ret;
}
public Set<Map.Entry<K, V>> entrySet() {
LinkedHashSet<Map.Entry<K, V>> ret = new LinkedHashSet<Map.Entry<K, V>>(size());
for (Collection<K> keys : valueToKeysMap.values()) {
for (final K k : keys) {
final V v = get(k);
ret.add(new Map.Entry<K,V>() {
public K getKey() {
return k;
}
public V getValue() {
return v;
}
public V setValue(V v) {
throw new UnsupportedOperationException();
}
});
}
}
return ret;
}
}
17
确定斯蒂芬的解决方案非常棒,但对于那些不能使用 Guava 的人来说:
这是我按值排序 Map 的解决方案 . 此解决方案处理两倍相同值的情况等...
// If you want to sort a map by value, and if there can be twice the same value:
// here is your original map
Map<String,Integer> mapToSortByVa
30 回答
一些简单的更改,以便使用具有重复值的对的排序映射 . 在比较方法(类ValueComparator)中,当值相等时,不返回0但返回比较2个键的结果 . 键在 Map 中是不同的,因此您可以成功保留重复值(顺便按键排序) . 所以上面的例子可以像这样修改:
主要问题 . 如果您使用第一个答案(Google将您带到此处),请更改比较器以添加相等的子句,否则您无法通过键从sorted_map获取值:
这太复杂了 . Map 不应该按照Value对它们进行排序 . 最简单的方法是创建自己的类,以满足您的要求 .
在示例中,您应该在*所在的位置添加TreeMap比较器 . 但是通过java API,它只为比较器提供键,而不是值 . 此处所述的所有示例均基于2个 Map . 一个哈希和一个新树 . 这很奇怪 .
这个例子:
因此,以这种方式将 Map 更改为集合:
你将创建类
Results
,和比较者类:
这样您就可以轻松添加更多依赖项 .
最后一点我将添加简单的迭代器:
根据上下文,使用
java.util.LinkedHashMap<T>
来记住项目放入 Map 的顺序 . 否则,如果您需要根据其自然顺序对值进行排序,我建议您维护一个单独的List,可以通过Collections.sort()
进行排序 .创建自定义比较器并在创建新TreeMap对象时使用它 .
在主函数中使用以下代码
输出:
而不是使用
Collections.sort
,我建议使用Arrays.sort
. 实际上Collections.sort
的作用是这样的:它只是在列表中调用
toArray
然后使用Arrays.sort
. 这样,所有映射条目将被复制三次:一次从映射到临时列表(无论是LinkedList还是ArrayList),然后到临时数组,最后到新映射 .我的解决方案省略了这一步,因为它不会创建不必要的LinkedList . 这是代码,通用友好和性能最佳:
要使用Java 8中的新功能实现此目的:
条目按照给定的比较器的值排序 . 或者,如果您的值可以相互比较,则不需要明确的比较器:
返回的列表是调用此方法时给定映射的快照,因此两者都不会反映对另一个的后续更改 . 对于 Map 的实时可迭代视图:
返回的iterable在每次迭代时都会创建给定映射的新快照,因此除非进行并发修改,否则它将始终反映映射的当前状态 .
由于 TreeMap<> does not work 对于可以相等的值,我使用了这个:
您可能希望将 list 放在 LinkedHashMap 中,但如果您're only going to iterate over it right away, that'多余的......
基于@devinmoore代码,使用泛型并支持升序和降序排序的 Map 排序方法 .
虽然我同意对 Map 进行排序的不断需要可能是一种气味,但我认为以下代码是最简单的方法,而不使用不同的数据结构 .
}
这是一个令人尴尬的不完整的单元测试:
}
结果是Map.Entry对象的排序列表,您可以从中获取键和值 .
我已经合并了user157196和Carter Page的解决方案:
这个问题已经有很多答案了,但是没有一个给我提供了我正在寻找的东西,一个 Map 实现返回按关联值排序的键和条目,并将此属性维护为键,并在映射中修改值 . 两个other questions特别要求这个 .
我编写了一个通用的友好示例来解决这个用例 . 此实现不遵守Map接口的所有 Contract ,例如反映从原始对象中的keySet()和entrySet()返回的集合中的值更改和删除 . 我觉得这样的解决方案太大而无法包含在Stack Overflow答案中 . 如果我设法创建一个更完整的实现,也许我会将它发布到Github,然后链接到这个答案的更新版本 .
确定斯蒂芬的解决方案非常棒,但对于那些不能使用 Guava 的人来说:
这是我按值排序 Map 的解决方案 . 此解决方案处理两倍相同值的情况等...