【问题标题】:How to create List<T> to Map<String, T> instead of Map<String, List<T>>?如何创建 List<T> 到 Map<String, T> 而不是 Map<String, List<T>>?
【发布时间】:2019-02-11 22:54:46
【问题描述】:

我遇到了需要将List&lt;Book&gt; 转换为Map&lt;String, Book&gt; 的情况,我能找到的唯一解决方案是如何执行Map&lt;String, List&lt;Book&gt;&gt;

类本身看起来如下(我省略了 getter/setter 和构造函数):

public class Book {
    private String asin;
    private String author;
    private String title;
}

我想通过特定的唯一键映射所有书籍,所以重复的概率要么可以忽略,要么0

我试着这样做:

    Map<String, Book> booksByAsinAndTitle = books.stream()
        .collect(Collectors.groupingBy((book) -> book.getAsin() + "||" + book.getTitle()))
        .entrySet()
        .stream()
        .collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue().get(0)));

它可以工作,但它看起来很丑陋,难以阅读,而且在代码库中也不是很好,因为它可能会让我的同事感到困惑。有没有更好的方法java 8 达到同样的效果?

【问题讨论】:

    标签: java java-8 java-stream


    【解决方案1】:

    使用toMap 代替groupingBy

    Map<String, Book> booksByAsinAndTitle = 
        books.stream()
             .collect(Collectors.toMap(b -> b.getAsin() + "||" + b.getTitle(),
                                       Function.identity()));
    

    如果您分组的键是唯一的,则没有理由使用groupingBy

    如果您的键可能不是唯一的,并且您仍希望 Map 包含与给定键匹配的第一个值,请添加一个合并函数:

    Map<String, Book> booksByAsinAndTitle = 
        books.stream()
             .collect(Collectors.toMap(b -> b.getAsin() + "||" + b.getTitle(),
                                       Function.identity()),
                                       (a,b) -> a);
    

    【讨论】:

    • 如果我的键不是唯一的,我决定取第一个元素,会有什么不同吗?
    • @DmytroChasovskyi 在这种情况下你必须添加一个合并功能
    • 好吧,我在发布我的答案时也在考虑这个问题。 (a,b) -&gt; a 会保证 .get(0) 吗?
    • @nullpointer 好吧,我认为它比 .get(0) 更正确,因为 groupingBy 没有说明给定组列表中元素的顺序。 .get(0) 可能会或可能不会返回与给定键匹配的第一本书(根据原始列表的顺序)。
    • @Eran 看起来不错,groupingBy 保持秩序。 stackoverflow.com/questions/39172981/…
    【解决方案2】:

    如果您确定键是唯一的,则无需对书籍进行分组。

    Map<String, Book> booksByAsinAndTitle = books.stream()
        .collect(Collectors.toMap(book -> book.getAsin() + "||" + book.getTitle(), x -> x));
    

    【讨论】:

      【解决方案3】:

      使用Map.putIfAbsentforEach 的更简单表示是:

      Function<Book, String> primaryKey = book -> book.getAsin() + "||" + book.getTitle();
      Map<String, Book> booksByAsinAndTitle = new HashMap<>();
      books.forEach(book -> booksByAsinAndTitle.putIfAbsent(primaryKey.apply(book), book));
      

      注意:这可确保针对某个键找到的第一个 book 保留在映射中。

      【讨论】:

        猜你喜欢
        • 2021-04-25
        • 2019-07-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-22
        • 1970-01-01
        • 1970-01-01
        • 2020-08-01
        • 1970-01-01
        相关资源
        最近更新 更多