Home > Blockchain >  How to group elements based their property using Java Stream API
How to group elements based their property using Java Stream API

Time:12-29

I have a list of natural numbers. How can I subgroup all the numbers divisible by 3, 5 and both, using Java Stream API?

For example:

ArrayList<Integer> list = new ArrayList<>();
list.add(24);
list.add(25);
list.add(45);
list.add(30);
list.add(3);
list.add(20);
list.add(5);

I want l3 = [3,24] , l5 = [5,20,25], l35 = [45,30]

Also, I don't want to call groupingBy() three times on the list as the list is really huge.

CodePudding user response:

I'd use a helper enum to describe the different possible classifications of the numbers, combined with Collectors.groupingBy():

import java.util.*;
import java.util.stream.*;

public class Demo {

    private enum Fizzbuzz {
        DIV_BY_THREE, DIV_BY_FIVE, DIV_BY_BOTH, DIV_BY_NEITHER;

        static public Fizzbuzz classify(int i) {
            if (i % 3 == 0) {
                return i % 5 == 0 ? DIV_BY_BOTH : DIV_BY_THREE;
            } else if (i % 5 == 0) {
                return DIV_BY_FIVE;
            } else {
                return DIV_BY_NEITHER;
            }
        }
    }

    public static void main(String[] args) {
        List<Integer> list = List.of(24, 25, 45, 30, 3, 20, 5);
        Map<Fizzbuzz, List<Integer>> groups =
            list.stream().collect(Collectors.groupingBy(Fizzbuzz::classify));
        System.out.println(groups);
    }
}

outputs

{DIV_BY_THREE=[24, 3], DIV_BY_FIVE=[25, 20, 5], DIV_BY_BOTH=[45, 30]}

CodePudding user response:

Reduce to a map

Use streams reduction. Here we can use the reduce(identityFunc, accumulationFunc, combiningFunc) variant:

The initial map contains 4 String keys mapped to empty List<Integer>:

  1. "I" for all unmapped (not-fizz-buzz-able) integers
  2. "I3" for divisible by 3
  3. "I5" for divisible by 5
  4. "I35" for divisible by 3 and 5

See runnable demo on IDEone:

Map<String, List<Integer>> fizzBuzz = new HashMap<>(3);
fizzBuzz.put("I", new ArrayList());
fizzBuzz.put("I3", new ArrayList());
fizzBuzz.put("I5", new ArrayList());
fizzBuzz.put("I35", new ArrayList());

list.stream().reduce(
       fizzBuzz,
       (map, e) -> {
          String key = "I"; // default key
          if (e % 3 == 0) key = "I3";
          if (e % 5 == 0) key = "I5";
          if (e % (3*5) == 0) key = "I35";
          map.get(key).add(e);
          return map;
        },
        (m, m2) -> {
            m.putAll(m2);
            return m;
        }
    );
        
System.out.println(fizzBuzz);

Prints the expected:

{I=[], I3=[24, 3], I35=[45, 30], I5=[25, 20, 5]}

See also: Java stream reduce to map

  • Related