2
votes

Java Lambda Stream group By et addition des valeurs entières / moyenne

J'ai une liste d'objets client (Customer: int id, bool isActive, int billingCount, ...) et je veux la somme et la moyenne de billingCount. Malheureusement, mon code n'a pas fonctionné. Comment dois-je changer le code pour qu'il fonctionne?

La somme et la moyenne devraient ressembler à ceci:

true 1234

false 1234

Error:(146, 17) java: no suitable method found for collect(java.util.stream.Collector<Customer,capture#1 of ?,java.util.Map<java.lang.Object,java.lang.Integer>>)
    method java.util.stream.Stream.<R>collect(java.util.function.Supplier<R>,java.util.function.BiConsumer<R,? super java.lang.Boolean>,java.util.function.BiConsumer<R,R>) is not applicable
      (cannot infer type-variable(s) R
        (actual and formal argument lists differ in length))
    method java.util.stream.Stream.<R,A>collect(java.util.stream.Collector<? super java.lang.Boolean,A,R>) is not applicable
      (inference variable T has incompatible bounds
        lower bounds: java.lang.Object,Customer
        lower bounds: java.lang.Boolean)

J'obtiens l'erreur suivante:

 Map<Boolean, Integer> sum = customer.stream()
                .map(c -> c.getIsActive())
                .collect(Collectors.groupingBy(c -> c, Collectors.summingInt(Customer::getBillingCount)));


Map<Boolean, Integer> average = customer.stream()
                .map(c -> c.getIsActive())
                .collect(Collectors.groupingBy(c -> c, Collectors.averagingInt(Customer::getBillingCount)));
    }


0 commentaires

3 Réponses :


3
votes

Avec vos appels map , vous convertissez votre Stream en Stream , ou en un flux de vrais vrais et des faux sur vos clients actifs et inactifs. Vous ne pouvez pas appeler le getBillingCount du client sur des booléens.

Vous pouvez utiliser le partitioningBy Collector pour regrouper par un valeur booléenne sans l'appel de map préalable. Le collecteur en aval peut être le summaryInt Collector pour collecter la somme et la moyenne (plus quelques autres dont vous n'avez peut-être pas besoin: count, max, min) en même temps.

Map<Boolean, Integer> stats = customer.stream()
    .collect(Collectors.partitioningBy(Customer::getIsActive,
                                       Collectors.summarizingInt(Customer::getBillingCount)));

Cela devrait vous donner les statistiques pour true et false dans une seule instruction.


0 commentaires

1
votes

Avez-vous vraiment besoin d'une carte pour les actifs et les inactifs? Qu'en est-il simplement de ceci:

IntSummaryStatistics summaryActive = customer.stream()
        .filter(Customer::getIsActive)
        .mapToInt(Customer::getBillingCount)
        .summaryStatistics();

long sumActive  = summary.getSum();
double averageActive = summary.getAverage();

Et vous pouvez faire de même avec inactive en remplaçant le filtre par .filter (c ->! C.getIsActive ())


0 commentaires

1
votes

Vous n'avez pas besoin d'utiliser la carte . Voir l'exemple ci-dessous:

{false=23, true=8}
{false=11.5, true=4.0}

Le code ci-dessus imprime:

List<Customer> customers = Arrays.asList(
        new Customer(10, true, 5),
        new Customer(11, true, 3),
        new Customer(20, false, 12),
        new Customer(21, false, 11));

Map<Boolean, Integer> sum = customers
        .stream()
        .collect(Collectors.groupingBy(Customer::isActive, Collectors.summingInt(Customer::getBillingCount)));
System.out.println(sum);

Map<Boolean, Double> avg = customers
        .stream()
        .collect(Collectors.groupingBy(Customer::isActive, Collectors.averagingInt(Customer::getBillingCount)));
System.out.println(avg);


0 commentaires