【问题标题】:How to sort HashMap entries values by multiple properties Java8 [duplicate]如何按多个属性Java8对HashMap条目值进行排序[重复]
【发布时间】:2018-04-12 08:56:03
【问题描述】:

如何按多个属性对 HashMap 条目进行排序。

假设我有一个带有键字符串和值作为对象的映射。

Map<String, UserMetrics> map = new HashMap<>
map.put("user10",new UserMetrics(1,100,111));
map.put("user3",new UserMetrics(10,330,444));
map.put("user11",new UserMetrics(333,100,555));
map.put("user1",new UserMetrics(1,111,433));

 public static class UsageMetrics implements Serializable {
        private long param1;
        private long param2;
        private long param3;....
 }

我想先按“param1”对用户进行排序,然后按“param2”排序

预期结果:

user10, UserMetrics(1,100,111)
user1,  UserMetrics(1,111,433))
user3,  UserMetrics(10,330,444));
user11, UserMetrics(333,100,555))

【问题讨论】:

  • 尝试使用Comparator.comparingthenComparing函数
  • @HadiJ Better comparingLongthenComparingLong

标签: java java-8


【解决方案1】:

您可以使用以下比较器进行排序:

Comparator
        .comparingLong(UserMetrics::getParam1)
        .thenComparingLong(UserMetrics::getParam2);

然而,困难在于您要对值进行排序,而不是对键进行排序。您似乎还需要键和值。为此,您可以制作地图条目集的副本并对其进行排序。类似的东西:

List<Map.Entry<String, UserMetrics>> sortedEntries = new ArrayList<>(map.entrySet());
Collections.sort(sortedEntries,
    Map.Entry.comparingByValue(
        Comparator
            .comparingLong(UserMetrics::getParam1)
            .thenComparingLong(UserMetrics::getParam2)));

或者,您也可以使用排序集合(如TreeSet)或排序流 - 通常您可以为“排序事物”提供自己的比较器。

另请注意,我使用的是comparingLong/thenComparingLong,这与人们只使用comparing/thenComparing 的其他答案不同。 comparing/thenComparing 的问题在于,如果你有像 long 这样的原始类型,comparing/thenComparing 基本上会将它们封装成像 Long 这样的包装类型,这是完全没有必要的。

【讨论】:

  • 按关键字排序。 OP 想要按值排序。
  • @HariMenon 啊,是的,我的错。
  • @HariMenon 已更正 - 让我们移除我们的 cmets,以免混淆。
  • @lexicore,谢谢 :) !
【解决方案2】:

您可以使用以下代码。我写的是使用Employee s 值对象,所以你可以使用你自己的Object

public class Main {
    public static void main(String[] args) throws InterruptedException {
        HashMap<String, Employee> map = new HashMap<>();
        Map<String, Employee> sortedMap = map.entrySet()
                                             .stream()
                                             .sorted(Entry.comparingByValue(Main::compare))
                                             .collect(Collectors.toMap(Entry::getKey, Entry::getValue,
                                                     (e1, e2) -> e1, LinkedHashMap::new));

    }

    public static int compare(Employee e1, Employee e2) {
        return e1.getAge() - e2.getAge();
    }
}

已编辑: 这是您可以使用Comparator#comparingthenComparing 进行排序的另一种方式。

Map<String, Employee> sortedMap = map.entrySet()
                                     .stream()
                                     .sorted(Entry.comparingByValue(
                                             Comparator.comparing(Employee::getAge)
                                                       .thenComparing(Employee::getSalary)))
                                     .collect(Collectors.toMap(Entry::getKey, Entry::getValue,
                                             (e1, e2) -> e1, LinkedHashMap::new));

【讨论】:

  • 这并没有解决问题的核心:如何比较多个属性。
  • Main:: compare 是一个比较器,您可以按照自己的意愿放置逻辑。您可以在 public static int compare(Employee e1, Employee e2) 方法中使用多个属性来开发您的逻辑。
  • 同样排序然后收集到HashMap 是没用的,因为HashMap 既不会保留排序也不会保留插入顺序。使用LinkedHashMap 保留插入顺序。 (更新:这在稍后的答案中得到了纠正。)
  • 你说得对,我已经更新了我的答案。
  • 是的,当然你可以把比较多个属性的逻辑放在Main.compare中。但你没有——尽管它是问题的核心。
【解决方案3】:

HashMap 不是按值排序的有效数据结构。但是如果你真的需要使用它,你可以尝试这样的方式:

map.entrySet().stream().sorted(Comparator.comparing(entry -> entry.getValue().param1)
                                                         .thenComparing(entry -> entry.getValue().param2)
                                                         .thenComparing(entry -> entry.getValue().param3))
        .collect(Collectors.toList());

【讨论】:

  • 更好comparingLong/thenComparingLong.
猜你喜欢
  • 2020-10-01
  • 2011-12-28
  • 2019-07-02
  • 2023-04-06
  • 2018-06-06
  • 2015-02-13
  • 1970-01-01
  • 2016-08-13
  • 1970-01-01
相关资源
最近更新 更多