如何使用 Java 流 API 基于 属性 对元素进行分组
How to group elements based their property using Java Stream API
我有一个自然数列表。如何使用 Java Stream API?
对所有可被 3、5 和两者整除的数字进行分组
例如:
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);
我想要 l3 = [3,24] , l5 = [5,20,25], l35 = [45,30]
此外,我不想在列表中调用 groupingBy()
三次,因为列表真的很大。
我会使用辅助枚举来描述数字的不同可能分类,并结合 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);
}
}
产出
{DIV_BY_THREE=[24, 3], DIV_BY_FIVE=[25, 20, 5], DIV_BY_BOTH=[45, 30]}
缩减为地图
使用streams reduction。
这里我们可以使用 reduce(identityFunc, accumulationFunc, combiningFunc)
变体:
初始映射包含 4 个 String
键映射到空 List<Integer>
:
"I"
对于所有未映射的(非 fizz-buzz-able)整数
"I3"
可被 3 整除
"I5"
可被 5 整除
"I35"
可被 3 和 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);
打印预期的:
{I=[], I3=[24, 3], I35=[45, 30], I5=[25, 20, 5]}
另请参阅:
我有一个自然数列表。如何使用 Java Stream API?
对所有可被 3、5 和两者整除的数字进行分组例如:
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);
我想要 l3 = [3,24] , l5 = [5,20,25], l35 = [45,30]
此外,我不想在列表中调用 groupingBy()
三次,因为列表真的很大。
我会使用辅助枚举来描述数字的不同可能分类,并结合 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);
}
}
产出
{DIV_BY_THREE=[24, 3], DIV_BY_FIVE=[25, 20, 5], DIV_BY_BOTH=[45, 30]}
缩减为地图
使用streams reduction。
这里我们可以使用 reduce(identityFunc, accumulationFunc, combiningFunc)
变体:
初始映射包含 4 个 String
键映射到空 List<Integer>
:
"I"
对于所有未映射的(非 fizz-buzz-able)整数"I3"
可被 3 整除"I5"
可被 5 整除"I35"
可被 3 和 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);
打印预期的:
{I=[], I3=[24, 3], I35=[45, 30], I5=[25, 20, 5]}
另请参阅: