【问题标题】:Update objects in one list based on values from second one using streams使用流根据第二个列表中的值更新一个列表中的对象
【发布时间】:2019-04-30 13:14:00
【问题描述】:

我有两个对应的列表:

public class BookOverallData {
    private Long idOfBook;
    private String title;
    private String authour;
    private BigDecimal basePrice;
    private Integer discountRate;
}

public class TimeDiscount {    
    private Long idOfBook;
    private Integer discountRate;    
}

Set<BookOverallData> booksToReturn
Set<TimeDiscount> actualPromotions

目标是汇总折扣,这意味着将 discountRateactualPromotions 添加到 discountRate 值从 booksToReturn 列表。两个列表中的对象都可以通过idOfBook匹配。

我就是这样解决的

booksToReturn.forEach(
            p -> {
                final Optional<TimeDiscount> promotion = actualPromotions.stream().filter(ap -> Objects.equals(ap.getIdOfBook(), p.getIdOfBook())).findFirst();
                promotion.ifPresent(ap -> p.setDiscountRate(ap.getDiscountRate() + p.getDiscountRate()));
            }
        );

我只是在探索流,我认为我的解决方案很笨拙。您将如何使用流和函数式方法以更优雅的方式解决这个问题?

【问题讨论】:

    标签: java java-8 functional-programming java-stream


    【解决方案1】:

    我首先创建一个从TimeDiscount::getIdOfBookTimeDiscount 的映射:

    Map<Long, TimeDiscount> accumulator = 
          actualPromotions.stream()
                         .collect(toMap(TimeDiscount::getIdOfBook, Function.identity()));
    

    那么我会这样做:

    booksToReturn.forEach(e -> {
           TimeDiscount timeDiscount = accumulator.get(e.getIdOfBook());
           if (timeDiscount != null) e.setDiscountRate(e.getDiscountRate() + timeDiscount.getDiscountRate());
    });
    

    或者如果您出于某种原因想继续使用Optional

    booksToReturn.forEach(e -> 
           Optional.ofNullable(accumulator.get(e.getIdOfBook()))
              .ifPresent(p -> e.setDiscountRate(e.getDiscountRate() + p.getDiscountRate()))
    );
    

    这改进了在actualPromotions.stream() 中对booksToReturn 的每个元素的低效查找。

    【讨论】:

      【解决方案2】:

      一种方法是使用:

      booksToReturn.forEach(p -> actualPromotions.stream()
                      .filter(actualPromotion -> actualPromotion.getIdOfBook().equals(p.getIdOfBook()))
                      .forEach(actualPromotion -> p.setDiscountRate(p.getDiscountRate() + actualPromotion.getDiscountRate())));
      

      假设actualPromotion.getIdOfBook()p.getIdOfBook() 在您的Sets 中是唯一的。

      【讨论】:

      • 很好,但我认为最好避免像@Aomine 那样为每个元素创建流。
      【解决方案3】:

      我没有测试过这个: 试试这个

        Map<Long,Integer> map1 = actualPromotions
         .stream() 
         .collect(Collectors.toMap(TimeDiscount::getIdOfBook,TimeDiscount::getDiscountRate));
      

      然后使用这张地图:

      booksToReturn.stream()
         .filter(b->map1.containsKey(b.getIdOfBook()))
         .map(p->{p.setDiscountRate(map1.get(p.getIdOfBook()) + p.getDiscountRate());return p;}) // .map(p->setSumDiscountRate(map1.get(p.getIdOfBook()) + p.getDiscountRate()))
         .collect(Collectors.toList());
      

      尝试在BookOverallData 类中声明一个新方法。

      public BookOverallData setSumDiscountRate(Integer dis){
        this.discountRate = dis;
        return this;
      }
      

      【讨论】:

        猜你喜欢
        • 2015-10-15
        • 2020-04-08
        • 1970-01-01
        • 1970-01-01
        • 2013-12-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多