2017-02-22 61 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))))); 

我想基于getWalletCreditNoteStatus如何组中的Java 8

的状态

有人可以最终降低是要么总和(如上面写的)或BigDecimal的列表中最后一个值引入条件对象请帮忙。


谢谢@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); 
} 

我现在要“for循环”删除并流逻辑应该只给我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

如何定义WalletCreditNoteVO的equals和hashcode? – 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

鉴于您的问题,这听起来很可笑。但是,当然你可以在完成功能中,只需要减少“某些东西”,而不是整数。然后,只需抓住地图的值。 – xiumeteo

+0

如果您从'收集器'静态地导入这些方法,它将更具可读性。 –