【问题标题】:Sort Java Map based on values in another map根据另一个地图中的值对 Java 地图进行排序
【发布时间】:2017-12-20 23:21:06
【问题描述】:

作为输入,我有对象列表,每个对象都有名称和地图:

1)
  Name: m1

  Map: {"c1": 3,
 "c2": 24
 "c3": 12}

2) Name: m2

Map: {"c1": "A",
 "c2": "B",
 "c3": "C"}

3) Name: m3

Map: {"c1": 3.4,
 "c2": 4.6,
 "c3": 12.3}

我需要什么作为输出,我需要根据名为 m1 的地图中的值对所有 3 个地图进行排序

首先,我想对 object#1(m1) 按值降序进行排序(我可以在这里使用 LinedHashMap):

{"c1": 3, "c2": 24, "c3": 12}  =>  {"c2": 24, "c3": 12, "c1": 3} 

现在,我希望对象#2 的映射和对象#3 的映射中的元素也按相同的键顺序排序 - C2、C3、C1。所以基本上我想要重新排序 2 个地图,以便顺序是 C2、C3、C1(与 m1 中的顺序相同)和 NOT C1、C2、C3。

我怎样才能以最优雅的方式做到这一点?我有一些解决方案 - 但它们很混乱,并且有很多额外的步骤。

如果有关系:此列表将始终只有 3 个对象。 Map 中的元素数量可以不同,但​​ Map 中的键在 3 个 Map 中始终相同

【问题讨论】:

  • @ram。 TreeMap可以排序。
  • @tsolakp 不,它不能。它按其键排序。您不能根据地图的值对地图进行排序。

标签: java dictionary linked-list linkedhashmap


【解决方案1】:

所以您知道如何按值对Map 进行排序,也许可以通过阅读以下答案:Sort a Map by values (Java),其中 Java 8 版本的答案是:

m1sorted = m1.entrySet()
             .stream()
             .sorted(Map.Entry.comparingByValue(Collections.reverseOrder()))
             .collect(Collectors.toMap(
               Map.Entry::getKey,
               Map.Entry::getValue,
               (e1, e2) -> e1,
               LinkedHashMap::new
             ));

那么如何根据m1 的值对m2m3 进行排序?

简单:您提供一个 Comparatorsorted() 来比较这些值,例如

.sorted(Comparator.comparing(e -> m1.get(e.getKey())).reversed())

您可能必须明确指定e 的类型,因为推理引擎可能会丢失:comparing((Entry<String, String> e) ->

如果您不喜欢 Comparator.comparing()reversed(),以及推理问题,您可以使用 lambda。

这是所有代码,作为概念证明:

Map<String, Integer> m1 = new HashMap<>();
m1.put("c1", 3);
m1.put("c2", 24);
m1.put("c3", 12);

Map<String, String> m2 = new HashMap<>();
m2.put("c1", "A");
m2.put("c2", "B");
m2.put("c3", "C");

Map<String, Double> m3 = new HashMap<>();
m3.put("c1", 3.4);
m3.put("c2", 4.6);
m3.put("c3", 12.3);
Map<String, Integer> m1s =
        m1.entrySet()
          .stream()
          .sorted((e1, e2) -> Integer.compare(e2.getValue(), e1.getValue()))
          .collect(Collectors.toMap(Map.Entry::getKey,
                                    Map.Entry::getValue,
                                    (e1, e2) -> e1,
                                    LinkedHashMap::new));

Map<String, String> m2s =
        m2.entrySet()
          .stream()
          .sorted((e1, e2) -> Integer.compare(m1.get(e2.getKey()), m1.get(e1.getKey())))
          .collect(Collectors.toMap(Map.Entry::getKey,
                                    Map.Entry::getValue,
                                    (e1, e2) -> e1,
                                    LinkedHashMap::new));

Map<String, Double> m3s =
        m3.entrySet()
          .stream()
          .sorted((e1, e2) -> Integer.compare(m1.get(e2.getKey()), m1.get(e1.getKey())))
          .collect(Collectors.toMap(Map.Entry::getKey,
                                    Map.Entry::getValue,
                                    (e1, e2) -> e1,
                                    LinkedHashMap::new));
System.out.println(m1s);
System.out.println(m2s);
System.out.println(m3s);

输出

{c2=24, c3=12, c1=3}
{c2=B, c3=C, c1=A}
{c2=4.6, c3=12.3, c1=3.4}

注意 e2e1 在 lambdas 中是如何颠倒的,从而导致降序。

当然,最好使用Java的面向对象特性,并且只有一个Map来表示具有三个字段值的对象。

【讨论】:

  • 这一切都很好,但它实际上并没有对地图进行排序。
  • @EJP 它实际上对地图进行了排序。当然,每次添加/更新值时都必须重做排序,但这是最接近按值排序的 Map 的方法。从来没有说过它是有效的,但它就是这样......
  • @Andreas 感谢您的帮助。我喜欢你的方法,但我认为这条线并不完全符合我在 m2s 和 m3s 中的预期: .sorted((e1, e2) -> Integer.compare(m1.get(e2.getKey()) , m1.get(e1.getKey()))) 似乎它是根据 m1s 地图的 VALUES 而不是 KEYS 对 m2s 和 m3s 地图进行排序的。我需要它按 m1s 地图的键排序。如何创建这样的比较器?
  • @Bilberryfm 你说“我需要根据中的值对所有3个地图进行排序名称为m1的地图” .这就是这段代码的作用:参见“输出”。 m1 的值按降序排列是 24, 12, 3,因此 所有 3 个映射中的键必须按 c2, c3, c1 的顺序排列。
猜你喜欢
  • 1970-01-01
  • 2021-09-13
  • 2015-11-07
  • 2021-10-07
  • 1970-01-01
  • 2013-10-31
  • 2011-09-26
  • 2021-07-20
  • 2014-12-14
相关资源
最近更新 更多