【问题标题】:java 8 stream collect max object and distinct by Propertyjava 8流收集最大对象并按属性区分
【发布时间】:2020-02-06 15:18:57
【问题描述】:

这里有一些列表

List<Book> list = new ArrayList<>();
{
   list.add(new Book("Core Java", 200));
   list.add(new Book("Core Java", 500));
   list.add(new Book("Core Java", 800));
   list.add(new Book("Learning Freemarker", 150));          
   list.add(new Book("Learning Freemarker", 1350));   
   list.add(new Book("Learning Freemarker", 1250));   
   list.add(new Book("Spring MVC", 300));
   list.add(new Book("Spring MVC", 600)); 
   list.add(new Book("Spring MVC", 1600));
}

我想显示这样的书单

Core Java", 800
Learning Freemarker", 1350
Spring MVC", 1600

每一个元素

list .stream().distinct()
     .sorted(Comparator.comparing(Book::bookname)
     .thenComparing(Book::getPrice)).collect(Collectors.toList());

此代码仅排序。

【问题讨论】:

  • 请出示Book类的代码。你有 equalshashCode 覆盖吗?
  • 书是样本类private string bookname ; private string price;它完成了;
  • @user3066285 - @ernest_k 主要感兴趣的是 equalshashcode 实现,如果您因为在示例代码中使用了 distinct 而覆盖了它们。

标签: java foreach java-8 java-stream


【解决方案1】:

首先你可以在Book名字上进行分组并收集到Map&lt;String, List&lt;Book&gt;&gt;,然后从map.values()收集每种类型的最高价格书

List<Book> books = list.stream()
                       .collect(Collectors.groupingBy(Book::getName))
                       .values()
                       .stream()
                       .map(book -> Collections.max(book, Comparator.comparingInt(Book::getCost)))
                       .collect(Collectors.toList());

@Holger 使用Collectors.toMap 建议的其他解决方案将比收集和查找最大元素更有效

List<Book> books = list.stream()
            .collect(Collectors.collectingAndThen(
                    Collectors.toMap(Book::getName, Function.identity(),
                            BinaryOperator.maxBy(Comparator.comparingInt(Book::getCost))),
                    m -> new ArrayList<>(m.values())));

【讨论】:

  • 谢谢。你节省了我的时间。
  • 也可以使用groupingreduce 在一次收集操作中执行比较,然后进一步从中获取值。正如我所记得和相关的,使用toMap 而不是这样的分组和减少组合仍然更好。再次链接Q&A
  • 简而言之,List&lt;Book&gt; books = list.stream() .collect(Collectors.collectingAndThen( Collectors.toMap(Book::getName, Function.identity(), BinaryOperator.maxBy( Comparator.comparing(Book::getPrice))), m -&gt; new ArrayList&lt;&gt;(m.values())));
  • 谢谢@Holger 我正在尝试类似的东西,但你明白了
【解决方案2】:

distinct and then using 排序意味着将选择所有不同的书籍(不仅仅是按名称),然后进一步排序仍然不会删除输入列表中的其他条目,直到您以某种方式减少它们。进一步基于所需的输出,这不应该是要走的路。

您可以寻找的是使用bookName 作为属性来检查唯一性,然后合并书籍比较它们的价格并将它们收集到我们的最终结果。

使用toMap 的代码相当简单,例如:

List<Book> distinctMaxPriceBooks = new ArrayList<>(list.stream()
        .collect(Collectors.toMap(Book::getBookName, Function.identity(),
                (b1, b2) -> b1.getPrice() >= b2.getPrice() ? b1 : b2))
        .values());

当然,如果需要的话,可以根据名称对它们进行排序。

【讨论】:

    【解决方案3】:

    使用max 方法并打印排序结果的版本。

     list.stream()
            .collect(Collectors.groupingBy(Book::getaString))
            .values()
            .stream()
                .map( (books) -> books.stream().max(Comparator.comparingInt(Book::getaNumber)).get())
                .sorted(Comparator.comparingInt(Book::getaNumber))
                .forEach(System.out::println);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多