如何对 Java 中的对象进行分组 8
How to group objects in Java 8
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
的状态引入最终归约的条件是 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 loop',流逻辑应该只给我一个 WalletCreditNoteVO 列表,而不是 WalletCreditNoteVO 的 Map 作为键和 BigDecimal 作为值,值直接在 WalletCreditNoteVO 中设置
再次感谢大家(我无法在我的评论中添加代码,所以在此处添加)。
所以我对你的案例进行了测试,我创建了一个与你的相似的虚拟 class:
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);
})));
我认为这没问题,但也许有人对如何处理您的问题有更好的想法。
如果您需要澄清,请联系我 :)
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
的状态引入最终归约的条件是 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 loop',流逻辑应该只给我一个 WalletCreditNoteVO 列表,而不是 WalletCreditNoteVO 的 Map 作为键和 BigDecimal 作为值,值直接在 WalletCreditNoteVO 中设置
再次感谢大家(我无法在我的评论中添加代码,所以在此处添加)。
所以我对你的案例进行了测试,我创建了一个与你的相似的虚拟 class:
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);
})));
我认为这没问题,但也许有人对如何处理您的问题有更好的想法。 如果您需要澄清,请联系我 :)