#java #collections #java-8 #java-stream
Вопрос:
Давайте возьмем для примера у меня есть список транзакций, который содержит txnId, код платежа, сумму. Вывод должен быть по каждому платежному коду с указанием собранной суммы.
Я попытался сгруппировать его на основе кода платежа в качестве ключа и списка суммы для кода платежа, но я не могу его уменьшить.
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
class Payment {
Integer txnId;
String paymentCode;
Integer amount;
Payment(Integer txnId, String paymentCode, Integer amount) {
this.txnId = txnId;
this.paymentCode = paymentCode;
this.amount = amount;
}
public String getPaymentCode() {
return this.paymentCode;
}
public Integer getAmount() {
return this.amount;
}
@Override
public String toString() {
return "Payment [txnId=" txnId ", paymentCode=" paymentCode ", amount=" amount "]";
}
}
public class ListGroupingSum {
public static void main(String[] args) {
List<Payment> payments = new ArrayList<>();
payments.add(new Payment(100, "GPAY", 100));
payments.add(new Payment(101, "CC", 200));
payments.add(new Payment(102, "PAYTM", 300));
payments.add(new Payment(103, "GPAY", 400));
payments.add(new Payment(104, "CC", 500));
// @formatter:off
Map<String, List<Integer>> paymentListByCodeAndAmount = payments.stream()
.collect(Collectors.groupingBy(Payment::getPaymentCode, Collectors.mapping(Payment::getAmount, Collectors.toList())));
System.out.println(paymentListByCodeAndAmount);
//System.out.println(paymentListByCodeAndAmount.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
// @formatter:on
}
}
Что дает результат
{CC=[200, 500], GPAY=[100, 400], PAYTM=[300]}
Но, ожидание-это
{CC=700, GPAY=500, PAYTM=300}
Ответ №1:
Map<String, Integer> paymentListByCodeAndAmount = payments.stream()
.collect(groupingBy(Payment::getPaymentCode, summingInt(Payment::getAmount)));
(с точными ожидаемыми результатами)
Действительно, summingInt
есть коллектор, куда groupingBy
поместят каждую группу, вы можете «суммировать» или что угодно.
Например, если данные группы не являются непосредственно целыми числами, вы можете сопоставить:
Map<String, Integer> paymentListByCodeAndAmount = payments.stream()
.collect(groupingBy(Payment::getPaymentCode,
mapping(p -> p.amount * p.txnId,
summingInt(x -> x))));
прочитано как «с платежами в виде потока, группировка по коду платежа, возьмите произведение суммы и txnId и дайте мне общую сумму».
Но, конечно, существуют миллионы комбинаций, вместо этого просто суммируйте, что вы могли бы суммировать (мин, макс, среднее значение,…) и что-то с этим сделать:
Map<String, Double> paymentListByCodeAndAmount = payments.stream()
.collect(groupingBy(Payment::getPaymentCode,
collectingAndThen(summarizingInt(p -> p.amount * p.txnId),
IntSummaryStatistics::getAverage)));
прочитано как «с платежами в виде потока, группировка по коду платежа, суммируйте произведение суммы и идентификатора txnId, а затем дайте мне среднее значение».
Комментарии:
1. Именно то, чего я хотел. Есть ли какая-либо альтернатива этому, например, функциональный интерфейс BinaryOperator, который можно настроить? Прошу только о понимании
2. Я обновил свои ответы, но на самом
Collectors
деле это DSL , так что есть миллионы различных возможностей.