首页 > 解决方案 > Java 按某些键的值对映射进行排序

问题描述

如何实现Comparator按某些键值对地图列表进行排序?我的目标是任意排序两个列表,以便我可以比较不属于排序的其他字段。

例如,假设我有这两个地图列表,我想按名字和姓氏排序。

+-----------+--------+-------+-------+
| List 1    | Map 1  | Map 2 | Map 3 |
+-----------+--------+-------+-------+
| firstName | John   | Eric  | John  |
| lastName  | Miller | Smith | Davis |
| age       | 17     | 19    | 35    |
+-----------+--------+-------+-------+

+-----------+--------+-------+-------+
|  List 2   | Map 1  | Map 2 | Map 3 |
+-----------+--------+-------+-------+
| firstName | Eric   | John  | John  |
| lastName  | Smith  | Davis | Miller|
| age       | 53     | 38    | 26    |
+-----------+--------+-------+-------+

在我对它进行排序之后,现在我可以将 List 1 的 Map 1 与 List 2 的 Map 2 进行比较,看看有什么不同。

所以我有一个实现比较器的类,如下所示:

// Note that the values may not implement Comparable
public class PersonComparator implements Comparator<Map<String, Object>> {
    private List<String> sortKeys = Arrays.asList("firstName", "lastName");

    @Override
    public int compare(Map<String, Object> map1, Map<String, Object> map2) {
        Map<String, Object> keyValue1 = new HashMap<>();
        sortKeys.forEach(key -> keyValue1.put(key, map1.get(key)));

        Map<String, Object> keyValue2 = new HashMap<>();
        sortKeys.forEach(key -> keyValue2.put(key, map2.get(key)));

        return keyValue2.hashCode() - keyValue1.hashCode();
    }
}

调用sort每个列表将导致以下结果:

+-----------+--------+-------+-------+
| List 1    | Map 1  | Map 2 | Map 3 |
+-----------+--------+-------+-------+
| firstName | John   | Eric  | John  |
| lastName  | Miller | Smith | Davis |
| age       | 17     | 19    | 35    |
+-----------+--------+-------+-------+

+-----------+--------+-------+-------+
| List 2    | Map 1  | Map 2 | Map 3 |
+-----------+--------+-------+-------+
| firstName | John   | Eric  | John  |
| lastName  | Miller | Smith | Davis |
| age       | 26     | 53    | 38    |
+-----------+--------+-------+-------+

但是列表的顺序永远不会改变......我做错了什么?

标签: javasortingcomparator

解决方案


最终,您的排序是基于键的哈希码 - 不一定与它们的值相关的排序(即,“较小的”字符串可以有更大的哈希码,反之亦然)。

相反,您应该根据值本身进行排序,即使这意味着将Object您必须的值显式转换为可比较值:

Comparator<Map<String, Object>> personComparator =
    Comparator.comparing(m -> (String) m.get("firstName"))
              .thenComparing(m -> (String) m.get("lastName"));

推荐阅读