Java 8 - Group a list and find the count

java 8 group by multiple fields
java-stream group by count
java 8 group by multiple fields and sum
java stream group by sum bigdecimal
java 8 multi level grouping
java stream group by max
grouping by java 8
java stream group by count filter

I have a list of result. I need to find the passed results count. But there is a relation between some items in list. For Example. I have list like

1.0 - false
2.0 - true
3.0 - false
4.0 - true
1.1 - true
3.1 - true

Then the passed count should be 2 and not the 4. Because I want to group the list based on id (1,1.2,1.3,1.xx in to single group) and mark it as pass if all the items in the group is pass . I have tried group using groupingBy and I have got a map of my expected behavior. I can iterate the map and get the count. But I want to know is there any way I can do this simply using Java 8.

public class Main {

static class Resultx {

    double id = 1;

    Boolean passed = false;

    public void setId(double id) {
        this.id = id;
    }

    public double getId() {
        return id;
    }

    public void setAsPassed() {
        this.passed = true;
    }

    public Boolean getPassed() {
        return passed;
    }

    @Override
    public String toString() {
        return getId() + " - " + getPassed();
    }
}


public static void main(String[] args) {
    List<Resultx> results = new ArrayList<>();
    for (int i = 1; i < 5; i++) {
        Resultx result = new Resultx();
        result.setId(i);
        if (i % 2 == 0) {
            result.setAsPassed();
        }
        results.add(result);
    }
    for (int i = 1; i < 5; i += 2) {
        Resultx result = new Resultx();
        result.setId(i + .1);
        result.setAsPassed();
        results.add(result);
    }
    System.out.println(results.size());
    results.forEach(System.out::println);
    System.out.println(results.stream().filter(Resultx::getPassed).count());
    System.out.println(results.stream().filter(e -> !e.getPassed()).count());
    System.out.println(results.stream().collect(Collectors.groupingBy(r -> (int) (r.getId()))));
}
}

Output

Total count - 6
1.0 - false
2.0 - true
3.0 - false
4.0 - true
1.1 - true
3.1 - true
Total pass count  - 4
Total fail count - 2
{1=[1.0 - false, 1.1 - true], 2=[2.0 - true], 3=[3.0 - false, 3.1 - true], 4=[4.0 - true]}

I want Overall pass count and overall fail count. which is 2 and 2

There are some strange things about your code, like using a double ID, which you just cast to int in your grouping operation or using a Boolean for you passed property instead of just boolean. Using the reference type Boolean, opens the opportunity to be null, which you would have to handle, if this possibility is intended. Otherwise, just use boolean.

It’s also not clear, what result you actually want. The example is not sufficient to describe it.

If you only want to count the groups, where true means "all where true" and false means "some where false", you can do it as simple as

Map<Boolean,Long> counts = results.stream()
    .collect(Collectors.collectingAndThen(
        Collectors.toMap(r -> (int)r.getId(), Resultx::getPassed, Boolean::logicalAnd),
        m -> m.values().stream()
            .collect(Collectors.partitioningBy(b -> b, Collectors.counting()))
    ));

If you want to count the elements of the groups, it gets more complicated.

int totalPassedCount = results.stream()
    .collect(Collectors.collectingAndThen(Collectors.groupingBy(r -> (int)r.getId(),
        Collector.of(() -> new Object() { int count = 0; boolean pass = true; },
            (o, r) -> { o.count++; o.pass &= r.getPassed(); },
            (x, y) -> { x.count += y.count; x.pass &= y.pass; return x; },
            o -> o.pass? o.count: 0
        )),
        (Map<Integer,Integer> x) -> x.values().stream().mapToInt(i -> i).sum()
    ));
System.out.println(totalPassedCount);

This uses a custom collector as downstream collector for groupingBy. This custom collector collects into an object holding the element count and whether all elements passed, then, in a finishing step, it replaces these object with the count, if all elements of the group passed or zero if not. Then, a finishing step is added to the groupingBy collector which will sum up all these values.


Above solution is for getting the passed counts, as you asked for in the beginning of your question. Since you’re asking for both at the end, you could use

Map<Boolean,Integer> counts = results.stream()
    .collect(Collectors.collectingAndThen(Collectors.groupingBy(r -> (int)r.getId(),
        Collector.of(() -> new Object() { int count = 0; boolean pass = true; },
            (o, r) -> { o.count++; o.pass &= r.getPassed(); },
            (x, y) -> { x.count += y.count; x.pass &= y.pass; return x; }
        )),
        m -> m.values().stream().collect(
            Collectors.partitioningBy(o -> o.pass, Collectors.summingInt(o -> o.count)))
    ));

for getting both.

Or, as it’s tricky to get the intended rule from a single example,

Map<Boolean,Integer> counts = results.stream()
    .collect(Collectors.collectingAndThen(Collectors.groupingBy(r -> (int)r.getId(),
        Collector.of(() -> new Object() { int passed, failed; },
            (o, r) -> { if(r.getPassed()) o.passed++; else o.failed++; },
            (x, y) -> { x.passed += y.passed; x.failed += y.failed; return x; }
        )),
        m -> m.values().stream()
            .filter(o -> o.passed == 0 || o.failed == 0)
            .collect(Collectors.partitioningBy(o -> o.failed==0,
                Collectors.summingInt(o -> o.failed==0? o.passed: o.failed)))
    ));

this will only count passed and failed, if all elements of a group passed or failed. But since you said, you’d expect 2 and 2, you may remove the .filter(o -> o.passed == 0 || o.failed == 0) line. Then, it will count passed only if all elements of the groups passed, but count all failed, even when some elements of the group passed. Then, you’d get 2 and 2 as result.

Java 8 – Stream Collectors groupingBy examples, 1.1 Group by a List and display the total count of it. Java8Example1.java. package com.mkyong.java8; import java  Because I want to group the list based on id (1,1.2,1.3,1.xx in to single group) and mark it as pass if all the items in the group is pass . I have tried group using groupingBy and I have got a map of my expected behavior. I can iterate the map and get the count. But I want to know is there any way I can do this simply using Java 8.

Try this one

 Map<Boolean, Long> collect = results.stream()
                    .collect(Collectors.groupingBy(r -> (int) (r.getId()))).values()
                    .stream().map(l -> l.stream().allMatch(p -> p.getPassed()))
                    .collect(Collectors.partitioningBy(k -> k, Collectors.counting()));

            System.out.println(collect);

Which display:

{false=2, true=2}

Java 8 stream group by count, How do you count the number of occurrences of an element in a list Java 8? Here is different ways of java 8 stream group by count with examples like grouping, counting, filtering, summing, averaging, multi-level grouping. Example 1: Grouping by + Counting Collectors class provide static factory method groupingBy which provides a similar kind of functionality as SQL group by clause.

This is fairly easy, just sort the results based on the test numbers, and then count each group individually. The sorting shouldn't be that computationally complex as long as you are dealing with less than million(s) of tests.

And if a single 'test' within the 'group' fails, the group as a whole fails, and then just have a struct to store the results of each grouping.

Count frequency of elements in a List in Java, it, we always need to specify a property by which the grouping would be performed. This method provides similar functionality to SQL's GROUP BY clause. In this article, we will show you how to use Java 8 Stream Collectors to group by, count, sum and sort a List.. 1. Group By, Count and Sort. 1.1 Group by a List and display the total count of it.

I am not entirely sure this is the easiest way, but:

Map<Double, Boolean> map = new HashMap<>();
    map.put(1.0D, false);
    map.put(2.0D, true);
    map.put(2.1D, true);
    map.put(1.2D, true);

    Map<Boolean, Long> result = map.entrySet()
        .stream()
        .collect(Collectors.groupingBy(
                x -> Arrays.asList(Math.round(x.getKey()), x.getValue()),
                Collectors.counting()))
        .entrySet()
        .stream()
        .collect(Collectors.partitioningBy(
                e -> (Boolean) e.getKey().get(1),
                Collectors.counting()));


  System.out.println(result); // {false=1, true=2}

Collectors groupingBy() method in Java with Examples , A guide to Java 8 groupingBy Collector with usage examples. To group the blog posts in the blog post list by their type: summarizing collector that can be used in cases when we need to calculate the count, sum, minimum  In Java SE 6 or 7, in order to create a group of objects from a list, you need to iterate over the list, check each element and put them into their own respective list. You also need a Map to store these groups. When you got the first item for a new group, you create a list and put that item on the list, but when the group already exists in Map then you just retrieve it and store your element

Not sure if Java 8 collection API would be the easiest way to go, but here down an implementation allowing to count the number of positive and negative results:

System.out.println(
              results.stream()
                    .collect(Collectors.groupingBy(result -> (int) (result.getId())))
                    .values()
                    .stream()
                    .map(v -> v.stream().allMatch(Resultx::getPassed))
                    .collect(Collectors.groupingBy(b -> b, Collectors.counting()))
        );

How to Count by 1 in Java, Java 8 | Collectors counting() with Examples. Collectors counting() method is used to count the number of elements passed in the Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below. Prime numbers in a Linked list · How to Convert a Short value to String value in Java  A guide to Java 8 groupingBy Collector with usage examples. The Java 8 Stream API lets us process collections of data in a declarative way.. The static factory methods Collectors.groupingBy() and Collectors.groupingByConcurrent() provide us with functionality similar to the ‘GROUP BY' clause in the SQL language.

Java 8 identity function, …or simply wanted to discover more its potential uses, then this article For example, if we wanted to group Strings by their lengths, we could do "cc", "ddd"​); TreeMap<Integer, List<String>> result = strings.stream() this can be as easy as providing a custom counting() collector: Java 8 - The Bad Parts. Java 8 Stream: concat, count, sorted and distinct Example By Arvind Rai, November 19, 2014 On this page we will provide the examples of concat, count, sorted and distinct stream API methods of java 8. concat method is static and count, sorted and distinct methods are called on stream object created by stream() method calling on collection.

Guide to Java 8 groupingBy Collector, Returns a Collector accepting elements of type T that counts the number of input Returns a Collector implementing a "group by" operation on input elements of type List<String> people = people.stream().collect(collectingAndThen(toList(), For example, given a stream of Person , to calculate tallest person in each city: To count the number of elements in stream in Java 8, use either the Stream.count() or Collectors.counting() methods. 1. Java stream count list elements – Stream count() function The Stream interface has a default method called count() that returns a long.

Java 8, The Java Tutorials have been written for JDK 8. as average , sum , min , max , and count ) that return one value by combining the contents of a stream. a specific task, such as finding the average of values or grouping elements into categories. Sex, List<String>> namesByGender = roster .stream() .collect( Collectors. In this post, we will see how to count the frequency of the elements in a List in Java. We know that a Set stores only distinct entries. The idea is to get distinct elements in the list by inserting all elements in the Set and then call static method freq

Comments
  • what about the ones that go above .5, so is 1.6 treated as 1 or 2?
  • Using a double for an ID looks suspicious. So does using Boolean instead of boolean for passed. Do you plan to support null values for it?
  • Should be fairly easy. Iterate the values as Key value pairs where key is (int) floatValue; and value as a boolean operation - existingValueIfany && newBooleanValue. Now you would have K, V pairs with number and boolean value. Filter only true values and get count. I'm using mobile and thus couldn't type answer :(
  • The reason for double part is, assume there are tasks that has sub tasks, so it wouldbe 1.1,1.2....1.12 . The Result object would hold the results of the Tasks. I would need to print them in an order so went for that.
  • Yeah, I would have gone for boolean , I wont want null values, will change. thanks for that. Thanks for the detailed explanation. Yes I want true means "all where true" and false means "some where false"
  • The disadvantage is that this will collect all group elements into Lists first, just to perform a logical and of the passed property afterwards. This reduction can be done right in the first grouping step without the intermediate list creation.
  • Thanks @SEY_91 , though your answer straight to the point and it is what I expected, purely for the above point by Holger, I accepted his answer.
  • how will the give you the total results of false and true?
  • Depending on what exactly' you mean, you can count both in different structures, 1 for total 'overall' (two ints: overall_true, overall_false) and one for 'total within each group. For simplicity's sake I'd just use a hashmap (not ideal, but first collection most people learn) to store the values of each group's count.(checking beforehand that I'm not over-writing values)
  • You are just counting the groups, ignoring the element counts of your first grouping operation completely. I.e., you produce the groups [1, false], [2, true], [1, true], resulting in one false and two true value.
  • @Holger isn't this result what the OP expects? But I agree otherwise on the useless counting
  • I don’t know. The OP’s description is really ambiguous. There are so many things that happen to be 2… But if the OP only want to count the groups, it can be done much simpler. I’ve added a solution for that case at the beginning of my answer.
  • Basically the same as this answer.