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>
:
"I"
for all unmapped (not-fizz-buzz-able) integers"I3"
for divisible by 3"I5"
for divisible by 5"I35"
for divisible by 3 and 5
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