如何推广一种方法来对 Java 中的地图条目进行排序?

How to generalize a method to sort Map Entries in Java?

在我的代码中,我有几张地图。然后我有一个类似于下面的方法,它采用其中一张地图,按条目的值和 returns 顶部列表的条目进行排序,数量由参数给出。

示例:

如果输入图是这样的

并且我在参数中使用 quantity = 2 调用该方法,我得到了 2 个最高地图条目的列表,按降序排列

现在,我对每张地图都有一个这样的方法,它们的区别仅在于:

我能否以某种方式将其概括为只有一个相似的方法,能够接收任何类型?

private static Map<String, Double>      distances = new TreeMap<>();
private static Map<String, Integer>     titles    = new TreeMap<>();
private static Map<Integer, Integer>    hours     = new TreeMap<>();
private static Map<Date, Integer>       days      = new TreeMap<>();

public static List<Entry<String, Double>> getTopDistances(int quantity) {
    List<Map.Entry<String, Double>> all       = new ArrayList<>(distances.entrySet());
    List<Map.Entry<String, Double>> requested = new ArrayList<>();

    Collections.sort(all, new Comparator<Map.Entry<String, Double>>() {
        @Override
        public int compare(Entry<String, Double> e1, Entry<String, Double> e2) {
            return (e2.getValue().compareTo(e1.getValue()));
        }

    });

    int i = 0;
    while (all.iterator().hasNext() && ++i <= quantity) {
        requested.add(all.get(i - 1));
    }

    return requested;
}

我当然可以继续将所有方法分开,但我觉得有更好的方法。研究了泛型、通配符、集合和接口,我认为这是可行的方法,但我仍然需要推动。

你不能创建比较器来比较两个不同类型的可比较对象,所以你必须这样做:

private static Map<String, Double> distances = new TreeMap<>();
private static Map<String, Integer>     titles    = new TreeMap<>();
private static Map<Integer, Integer>    hours     = new TreeMap<>();
private static Map<Date, Integer>       days      = new TreeMap<>();

public static List<Map.Entry<String, Double>> getTopDistances(int quantity) {
    List<Map.Entry<String, Double>> all       = new ArrayList<>(distances.entrySet());
    List<Map.Entry<String, Double>> requested = new ArrayList<>();

    all.sort(naturalOrder());

    int i = 0;
    while (all.iterator().hasNext() && ++i <= quantity) {
        requested.add(all.get(i - 1));
    }

    return requested;
}

public static <T extends Comparable<? super T>> Comparator<Map.Entry<?,T> naturalOrder() {
    return (e1, e2) -> e2.getValue().compareTo(e2.getValue());
}

使用Java Streams,一行就可以生成您想要的从映射到最终列表的内容。下面我把它打包成一个更简洁的私有方法,但如果你愿意,你可以内联它。

因为你所有的值都是Comparable:

private <K, V extends Comparable<V>> List<Map.Entry<K,V>> getTop(Map<K,V> map, int quantity) {
    return map.entrySet().stream()
           .sorted((a,b) -> b.getValue().compareTo(a.getValue()))
           .limit(quantity)
           .collect(Collectors.toList());
} 

如果值类型不可比较,则需要将比较器作为附加参数传递:

private <K, V> List<Map.Entry<K,V>> getTop(Map<K,V> map, Comparator<V> cmp, int quantity) {
    return map.entrySet().stream()
           .sorted((a,b) -> cmp.compare(b,a))
           .limit(quantity)
           .collect(Collectors.toList());
}