我对Java比较陌生,经常发现需要对值进行Map<Key,Value>排序。

由于这些值不是唯一的,我发现自己将keySet转换为一个数组,并使用自定义比较器通过数组排序对该数组进行排序,该比较器根据与该键关联的值进行排序。

有没有更简单的方法?


当前回答

HashMap<String,Long>的最简单的暴力排序HashMap方法:您可以复制粘贴它,然后这样使用:

public class Test  {
    public static void main(String[] args)  {
        HashMap<String, Long> hashMap = new HashMap<>();
        hashMap.put("Cat", (long) 4);
        hashMap.put("Human", (long) 2);
        hashMap.put("Dog", (long) 4);
        hashMap.put("Fish", (long) 0);
        hashMap.put("Tree", (long) 1);
        hashMap.put("Three-legged-human", (long) 3);
        hashMap.put("Monkey", (long) 2);

        System.out.println(hashMap);  //{Human=2, Cat=4, Three-legged-human=3, Monkey=2, Fish=0, Tree=1, Dog=4}
        System.out.println(sortHashMap(hashMap));  //{Cat=4, Dog=4, Three-legged-human=3, Human=2, Monkey=2, Tree=1, Fish=0}
    }

    public LinkedHashMap<String, Long> sortHashMap(HashMap<String, Long> unsortedMap)  {
        LinkedHashMap<String, Long> result = new LinkedHashMap<>();

        //add String keys to an array: the array would get sorted, based on those keys' values
        ArrayList<String> sortedKeys = new ArrayList<>();
        for (String key: unsortedMap.keySet())  {
            sortedKeys.add(key);
        }

        //sort the ArrayList<String> of keys    
        for (int i=0; i<unsortedMap.size(); i++)  {
            for (int j=1; j<sortedKeys.size(); j++)  {
                if (unsortedMap.get(sortedKeys.get(j)) > unsortedMap.get(sortedKeys.get(j-1))) {
                    String temp = sortedKeys.get(j);
                    sortedKeys.set(j, sortedKeys.get(j-1));
                    sortedKeys.set(j-1, temp);
                }
            }
        }

        // construct the result Map
        for (String key: sortedKeys)  {
            result.put(key, unsortedMap.get(key));
        }

        return result;
    }
}

其他回答

这太复杂了。地图不应该按价值排序。最简单的方法是创建自己的类,以满足您的需求。

在下面的示例中,您应该在*所在的位置添加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()
        );
}

主要问题。如果您使用第一个答案(Google将您带到这里),请更改比较器以添加等号子句,否则无法按键从sorted_map中获取值:

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
    }

我们只需像这样对地图进行排序

            Map<String, String> unsortedMap = new HashMap<String, String>();

    unsortedMap.put("E", "E Val");
    unsortedMap.put("F", "F Val");
    unsortedMap.put("H", "H Val");
    unsortedMap.put("B", "B Val");
    unsortedMap.put("C", "C Val");
    unsortedMap.put("A", "A Val");
    unsortedMap.put("G", "G Val");
    unsortedMap.put("D", "D Val");

    Map<String, String> sortedMap = new TreeMap<String, String>(unsortedMap);

    System.out.println("\nAfter sorting..");
    for (Map.Entry <String, String> mapEntry : sortedMap.entrySet()) {
        System.out.println(mapEntry.getKey() + " \t" + mapEntry.getValue());

这还有一个额外的好处,即可以使用Java8进行升序或降序排序

import static java.util.Comparator.comparingInt;
import static java.util.stream.Collectors.toMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import java.util.stream.Stream;

class Utils {
    public static Map<String, Integer> sortMapBasedOnValues(Map<String, Integer> map, boolean descending) {
        int multiplyBy = (descending) ? -1: 1;
        Map<String, Integer> sorted =  map.entrySet().stream()
                .sorted(comparingInt(e -> multiplyBy * e.getValue() ))
                .collect(toMap(
                        Map.Entry::getKey, 
                        Map.Entry::getValue,
                        (a, b) -> { throw new AssertionError();},
                        LinkedHashMap::new
                    ));
        return sorted;
    }
}

当你有两个相等的项目时,投票给最多的答案不起作用。TreeMap保留相等的值。

示例:未排序地图

key/value: D/67.3
key/value: A/99.5
key/value: B/67.4
key/value: C/67.5
key/value: E/99.5

后果

key/value: A/99.5
key/value: C/67.5
key/value: B/67.4
key/value: D/67.3

所以省略了E!!

对我来说,它可以很好地调整比较器,如果它等于,则不返回0,而是返回-1。

在示例中:

类ValueComparator实现Comparator{地图库;公共ValueComparator(地图库){this.base=基数;}public int compare(对象a,对象b){如果((双)base.get(a)<(双)base.get(b)){返回1;}否则如果((双)base.get(a)==(双)base.get(b)){返回-1;}其他{返回-1;}}}

现在它返回:

未排序地图:

key/value: D/67.3
key/value: A/99.5
key/value: B/67.4
key/value: C/67.5
key/value: E/99.5

结果:

key/value: A/99.5
key/value: E/99.5
key/value: C/67.5
key/value: B/67.4
key/value: D/67.3

作为对《外国人》的回应(2011年11月22日):我将此解决方案用于整数Id和名称的映射,但想法是相同的,因此上面的代码可能不正确(我将在测试中编写并给您正确的代码),这是基于上面解决方案的map排序代码:

package nl.iamit.util;

import java.util.Comparator;
import java.util.Map;

public class Comparators {


    public static class MapIntegerStringComparator implements Comparator {

        Map<Integer, String> base;

        public MapIntegerStringComparator(Map<Integer, String> base) {
            this.base = base;
        }

        public int compare(Object a, Object b) {

            int compare = ((String) base.get(a))
                    .compareTo((String) base.get(b));
            if (compare == 0) {
                return -1;
            }
            return compare;
        }
    }


}

这是测试类(我刚刚测试了它,这适用于Integer,StringMap:

package test.nl.iamit.util;

import java.util.HashMap;
import java.util.TreeMap;
import nl.iamit.util.Comparators;
import org.junit.Test;
import static org.junit.Assert.assertArrayEquals;

public class TestComparators {


    @Test
    public void testMapIntegerStringComparator(){
        HashMap<Integer, String> unSoretedMap = new HashMap<Integer, String>();
        Comparators.MapIntegerStringComparator bvc = new Comparators.MapIntegerStringComparator(
                unSoretedMap);
        TreeMap<Integer, String> sorted_map = new TreeMap<Integer, String>(bvc);
        //the testdata:
        unSoretedMap.put(new Integer(1), "E");
        unSoretedMap.put(new Integer(2), "A");
        unSoretedMap.put(new Integer(3), "E");
        unSoretedMap.put(new Integer(4), "B");
        unSoretedMap.put(new Integer(5), "F");

        sorted_map.putAll(unSoretedMap);

        Object[] targetKeys={new Integer(2),new Integer(4),new Integer(3),new Integer(1),new Integer(5) };
        Object[] currecntKeys=sorted_map.keySet().toArray();

        assertArrayEquals(targetKeys,currecntKeys);
    }
}

以下是地图比较器的代码:

public static class MapStringDoubleComparator implements Comparator {

    Map<String, Double> base;

    public MapStringDoubleComparator(Map<String, Double> base) {
        this.base = base;
    }

    //note if you want decending in stead of ascending, turn around 1 and -1
    public int compare(Object a, Object b) {
        if ((Double) base.get(a) == (Double) base.get(b)) {
            return 0;
        } else if((Double) base.get(a) < (Double) base.get(b)) {
            return -1;
        }else{
            return 1;
        }
    }
}

这是一个测试用例:

@Test
public void testMapStringDoubleComparator(){
    HashMap<String, Double> unSoretedMap = new HashMap<String, Double>();
    Comparators.MapStringDoubleComparator bvc = new Comparators.MapStringDoubleComparator(
            unSoretedMap);
    TreeMap<String, Double> sorted_map = new TreeMap<String, Double>(bvc);
    //the testdata:
    unSoretedMap.put("D",new Double(67.3));
    unSoretedMap.put("A",new Double(99.5));
    unSoretedMap.put("B",new Double(67.4));
    unSoretedMap.put("C",new Double(67.5));
    unSoretedMap.put("E",new Double(99.5));

    sorted_map.putAll(unSoretedMap);

    Object[] targetKeys={"D","B","C","E","A"};
    Object[] currecntKeys=sorted_map.keySet().toArray();

    assertArrayEquals(targetKeys,currecntKeys);
}

当然,你可以让它更通用,但我只需要一个案例(地图)