Обновлять объекты в одном списке на основе значений из второго, используя потоки - PullRequest
0 голосов
/ 28 ноября 2018

У меня есть два соответствующих списка:

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 от actualPromotions до 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()));
            }
        );

Я просто исследую потоки, и я думаю, что мое решение комковато.Как бы вы решили эту проблему более элегантно, с использованием потоков и функционального подхода?

Ответы [ 3 ]

0 голосов
/ 28 ноября 2018

Сначала я бы создал отображение от 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() для каждого элемента booksToReturn.

0 голосов
/ 28 ноября 2018

Я не проверял это: Попробуйте это

  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;
}
0 голосов
/ 28 ноября 2018

Один из способов сделать это - использовать:

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 с.

...