使用流根据第二个列表中的值更新一个列表中的对象

时间:2018-11-28 15:17:27

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

我有两个对应的列表:

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

目标是汇总折扣,这意味着将discountRate中的actualPromotionsdiscountRate列表中的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()));
            }
        );

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

3 个答案:

答案 0 :(得分:3)

我首先创建一个从log4j.appender.rollingFile=org.apache.log4j.RollingFileAppender log4j.appender.rollingFile.File=c:/MyLoggingDir/application6.log log4j.appender.rollingFile.layout=org.apache.log4j.PatternLayout log4j.appender.rollingFile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %m%n log4j.appender.rollingFile.MaxFileSize=10MB log4j.appender.rollingFile.MaxBackupIndex=5 log4j.appender.rollingFile.append=true log4j.rootCategory=ALL, rollingFile TimeDiscount::getIdOfBook的映射:

TimeDiscount

那我要做:

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()中的低效率查找。

答案 1 :(得分:1)

一种实现方法是使用:

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

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

答案 2 :(得分:1)

我尚未对此进行测试: 试试这个

  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;
}