2017-02-22 9 views
-1
WalletCreditNoteVO a1 = new WalletCreditNoteVO(1L, 1L, "A", WalletCreditNoteStatus.EXPIRED, null, null, CreditNoteType.CAMPAIGN_VOUCHER, BigDecimal.ONE, BigDecimal.ONE, "GBP"); 
WalletCreditNoteVO a2 = new WalletCreditNoteVO(1L, 1L, "A", WalletCreditNoteStatus.EXPIRED, null, null, CreditNoteType.CAMPAIGN_VOUCHER, BigDecimal.ONE, BigDecimal.TEN, "GBP"); 
WalletCreditNoteVO a3 = new WalletCreditNoteVO(2L, 1L, "A", WalletCreditNoteStatus.EXPIRED, null, null, CreditNoteType.CAMPAIGN_VOUCHER, BigDecimal.ONE, BigDecimal.ONE, "GBP"); 
WalletCreditNoteVO a4 = new WalletCreditNoteVO(2L, 1L, "A", WalletCreditNoteStatus.EXPIRED, null, null, CreditNoteType.CAMPAIGN_VOUCHER, BigDecimal.ONE, BigDecimal.TEN, "GBP"); 

final List<WalletCreditNoteVO> walletCreditNoteVOs = Lists.newArrayList(a1, a2, a3, a4); 


Map<WalletCreditNoteVO, BigDecimal> collect2 = walletCreditNoteVOs.stream().collect(
     groupingBy(wr -> new WalletCreditNoteVO(wr.getCreditNoteId(), wr.getWalletCustomerId(), wr.getCreditNoteTitle(), 
         wr.getWalletCreditNoteStatus(), wr.getCreditNoteStartDate(), wr.getCreditNoteExpiryDate(), wr.getCreditNoteType(), wr.getCreditNoteValue(), wr.getCurrency()), 
       mapping(WalletCreditNoteVO::getAvailableBalance, 
         reducing(BigDecimal.ZERO, (sum, elem) -> sum.add(elem))))); 

Я хочу ввести условие для окончательного восстановления будет либо сумма (как написано выше) или последнего значения в списке BigDecimal на основе статуса getWalletCreditNoteStatusКак группировать объекты в Java 8

Может кто-то пожалуйста помоги.


Спасибо @xiumeteo. Ниже улучшается решением

Function<WalletCreditNoteVO, WalletCreditNoteVO> function = wr -> new WalletCreditNoteVO(wr.getCreditNoteId(), wr.getWalletCustomerId(), wr.getCreditNoteTitle(), 
     wr.getWalletCreditNoteStatus(), wr.getCreditNoteStartDate(), wr.getCreditNoteExpiryDate(), wr.getCreditNoteType(), wr.getCreditNoteValue(), wr.getCurrency()); 

final Map<WalletCreditNoteVO, BigDecimal> collectMap = 
     walletCreditNoteVOs.stream() 
       .collect(groupingBy(function, LinkedHashMap::new, Collectors.collectingAndThen(
         toList(), 
         (list) -> { 
          final List<BigDecimal> availableBalances = list.stream().map(WalletCreditNoteVO::getAvailableBalance).collect(toList()); 
          if (list.stream().allMatch(WalletCreditNoteVO::isStatusExpired)) { 
           return availableBalances.stream().filter(o -> o != null).reduce((a, b) -> b).orElse(null).abs(); 
          } else { 
           return availableBalances.stream().filter(o -> o != null).reduce(BigDecimal.ZERO, BigDecimal::add); 
          } 
         }))); 

List<WalletCreditNoteVO> walletCreditNoteVOGrouped = new ArrayList<>(); 
for(Map.Entry<WalletCreditNoteVO, BigDecimal> entry : collectMap.entrySet()){ 
    WalletCreditNoteVO key = entry.getKey(); 
    key.setAvailableBalance(entry.getValue()); 
    walletCreditNoteVOGrouped.add(key); 
} 

теперь я хочу, чтобы удалить «цикл» и поток логика должна просто дать мне один список WalletCreditNoteVO вместо Карту WalletCreditNoteVO как ключ и BigDecimal в качестве значения, с значением, установленным непосредственно в WalletCreditNoteVO

Спасибо всем снова (я не могу добавить код в свои комментарии, поэтому добавляю его здесь).

+0

вместо (sum, elem) -> sum.add (elem) just (sum, elem) -> elem даст мне последний элемент. Теперь, как сделать эти две операции условными на основе значения getWalletCreditNoteStatus. –

+1

Вам действительно нужно группировать объекты, создавая больше объектов через конструктор? Если equals определяется тем, что находится в конструкторе, вы можете просто использовать 'i -> i' lambda или' java.util.function.Function.identity() '. Теперь, чтобы сделать их условными, вам нужно перевернуть свой собственный сборник вместо «картографирования» - сборщика, который примет решение, которое будет использоваться для сбора данных. –

+0

Как определяются значения equals и hashcode из 'WalletCreditNoteVO'? – xiumeteo

ответ

1

Так что я тест для вашего дела, я создал фиктивный класс, который напоминает вами:

public static class Something{ 
     private String name; 
     private Integer sum; 
     private boolean checker; 

     public Something(String name, Integer sum, boolean checker) { 
      this.name = name; 
      this.sum = sum; 
      this.checker = checker; 
     } 

     public String getName() { 
      return name; 
     } 

     public boolean isChecker() { 
      return checker; 
     } 

     public Integer getSum() { 
      return sum; 
     } 

     @Override 
     public boolean equals(Object o) { 
      if (this == o) { 
       return true; 
      } 

      if (o == null || getClass() != o.getClass()) { 
       return false; 
      } 

      Something something = (Something) o; 

      return new EqualsBuilder().append(getName(), something.getName()).append(getSum(), something.getSum()).isEquals(); 
     } 

     @Override 
     public int hashCode() { 
      return new HashCodeBuilder(17, 37).append(getName()).append(getSum()).toHashCode(); 
     } 
    } 

И тогда я сделал этот небольшой тест

List<Something> items = Arrays.asList(new Something("name", 10, false), new Something("name", 14, true), new Something("name", 11, false), 
      new Something("name", 11, false), new Something("noName", 12, false)); 

final Map<Something, Integer> somethingToSumOrLastElement = 
    items.stream() 
    .collect(Collectors.groupingBy(Function.identity(), 
      Collectors.collectingAndThen(
       Collectors.toList(), // first we collect all your related items into a list 
       (list) -> { //this collector allow us to have a finisher, Function<List<Something>, Object>, let's define it 
        final List<Integer> integerStream = list.stream().map(Something::getSum).collect(Collectors.toList()); 
        if (list.stream().allMatch(Something::isChecker)) { // we check for the method you want to check 
         //you have to change this depending on required logic 
         //for this case if that's true for every element in the list, we do the reduce by summing 
         return integerStream.stream().reduce(0, (sum, next) -> sum + next); 
        } 
        //if not, we just get the last element of that list 
        return integerStream.stream().reduce(0, (sum, next) -> next); 
     }))); 

Я думаю, что это нормально, но возможно, у кого-то есть лучшая идея о том, как справиться с вашей проблемой. Пинг меня, если вам нужно уточнение :)

+0

Большое спасибо @xiumeteo. Ваш код помог. Действительно блестящее решение. Только один последний вопрос. Вместо карты Something как ключа и списка Sum в качестве значения, возможно ли иметь список Something с правильной суммой (либо суммой, либо последним значением), установленной на Something напрямую. Теперь мне нужно перебрать карту и создать другой список и установить значение в ключе. –

+0

Этот звук не соответствует вашей задаче. Но, конечно, вы можете, в функции финишера, все, что вам нужно сделать, это уменьшить с точки зрения «что-то», а не в терминах Integer. А затем просто возьмите значения Карты. – xiumeteo

+0

Если вы статически импортируете эти методы из 'Collectors', это будет более читаемо. –