对具有多个条件的对象列表进行分组
Group a list of objects with multiple conditions
public class Student {
String name;
int age;
}
我有一个 Student
对象的列表,我需要根据特定逻辑对它们进行分组:
- 将所有名字以“A”开头的学生分组
- 将所有姓名以“P”开头的学生分组
- 将年龄大于或等于 30 岁的所有学生分组
到目前为止我做了什么:
List<Student> students = List.of(
new Student("Alex", 31),
new Student("Peter", 33),
new Student("Antony", 32),
new Student("Pope", 40),
new Student("Michel", 30));
Function<Student, String> checkFunction = e -> {
if (e.getName().startsWith("A")) {
return "A-List";
} else if (e.getName().startsWith("P")) {
return "P-List";
} else if (e.getAge() >= 30) {
return "30's-List";
} else {
return "Exception-List";
}
};
Map<String, List<Student>> result = students.stream().collect(Collectors.groupingBy(checkFunction));
for (var entry : result.entrySet()) {
System.out.println(entry.getKey() + "---");
for (Student std : entry.getValue()) {
System.out.println(std.getName());
}
}
输出
A-List---
Alex
Antony
P-List---
Peter
Pope
30's-List---
Michel
我理解我所遵循的这个逻辑是错误的,这就是为什么 30 岁的列表没有正确填充的原因。 groupingBy()
真的可以吗?
这可以像 中那样处理,但您必须调整 checkFunction
以实际 return 每个 Student
的组。
private Stream<String> mapToGroups(Student e) {
Builder<String> builder = Stream.builder();
boolean isException = false;
if (e.getName().startsWith("A")) {
builder.add("A-List");
} else if (e.getName().startsWith("P")) {
builder.add("P-List");
} else {
isException = true;
}
if (e.getAge() >= 30) {
builder.add("30's-List");
} else if (isException) {
builder.add("Exception-List");
}
return builder.build();
}
但是,如果我们要在 flatMap()
调用中使用此函数,我们将在该过程中丢失 Student
。所以我们真正想要的是这个方法 return String<Map.Entry<String, Student>>
以便我们以后可以使用用于分组的键和用于收集组的值:
private Stream<Entry<String, Student>> mapToGroupEntries(Student e) {
Builder<Entry<String, Student>> builder = Stream.builder();
boolean isException = false;
if (e.getName().startsWith("A")) {
builder.add(new SimpleEntry<>("A-List", e));
} else if (e.getName().startsWith("P")) {
builder.add(new SimpleEntry<>("P-List", e));
} else {
isException = true;
}
if (e.getAge() >= 30) {
builder.add(new SimpleEntry<>("30's-List", e));
} else if (isException) {
builder.add(new SimpleEntry<>("Exception-List", e));
}
return builder.build();
}
我们现在可以将此函数用作 flatMap()
调用的一部分,将我们的 Stream<Student>
转换为 Stream<Entry<String, Student>>
,然后将它们分组:
Map<String, List<Student>> result = students.stream()
.flatMap(s -> mapToGroupEntries(s))
.collect(Collectors.groupingBy(Entry::getKey,
Collectors.mapping(Entry::getValue, Collectors.toList())));
public class Student {
String name;
int age;
}
我有一个 Student
对象的列表,我需要根据特定逻辑对它们进行分组:
- 将所有名字以“A”开头的学生分组
- 将所有姓名以“P”开头的学生分组
- 将年龄大于或等于 30 岁的所有学生分组
到目前为止我做了什么:
List<Student> students = List.of(
new Student("Alex", 31),
new Student("Peter", 33),
new Student("Antony", 32),
new Student("Pope", 40),
new Student("Michel", 30));
Function<Student, String> checkFunction = e -> {
if (e.getName().startsWith("A")) {
return "A-List";
} else if (e.getName().startsWith("P")) {
return "P-List";
} else if (e.getAge() >= 30) {
return "30's-List";
} else {
return "Exception-List";
}
};
Map<String, List<Student>> result = students.stream().collect(Collectors.groupingBy(checkFunction));
for (var entry : result.entrySet()) {
System.out.println(entry.getKey() + "---");
for (Student std : entry.getValue()) {
System.out.println(std.getName());
}
}
输出
A-List---
Alex
Antony
P-List---
Peter
Pope
30's-List---
Michel
我理解我所遵循的这个逻辑是错误的,这就是为什么 30 岁的列表没有正确填充的原因。 groupingBy()
真的可以吗?
这可以像 checkFunction
以实际 return 每个 Student
的组。
private Stream<String> mapToGroups(Student e) {
Builder<String> builder = Stream.builder();
boolean isException = false;
if (e.getName().startsWith("A")) {
builder.add("A-List");
} else if (e.getName().startsWith("P")) {
builder.add("P-List");
} else {
isException = true;
}
if (e.getAge() >= 30) {
builder.add("30's-List");
} else if (isException) {
builder.add("Exception-List");
}
return builder.build();
}
但是,如果我们要在 flatMap()
调用中使用此函数,我们将在该过程中丢失 Student
。所以我们真正想要的是这个方法 return String<Map.Entry<String, Student>>
以便我们以后可以使用用于分组的键和用于收集组的值:
private Stream<Entry<String, Student>> mapToGroupEntries(Student e) {
Builder<Entry<String, Student>> builder = Stream.builder();
boolean isException = false;
if (e.getName().startsWith("A")) {
builder.add(new SimpleEntry<>("A-List", e));
} else if (e.getName().startsWith("P")) {
builder.add(new SimpleEntry<>("P-List", e));
} else {
isException = true;
}
if (e.getAge() >= 30) {
builder.add(new SimpleEntry<>("30's-List", e));
} else if (isException) {
builder.add(new SimpleEntry<>("Exception-List", e));
}
return builder.build();
}
我们现在可以将此函数用作 flatMap()
调用的一部分,将我们的 Stream<Student>
转换为 Stream<Entry<String, Student>>
,然后将它们分组:
Map<String, List<Student>> result = students.stream()
.flatMap(s -> mapToGroupEntries(s))
.collect(Collectors.groupingBy(Entry::getKey,
Collectors.mapping(Entry::getValue, Collectors.toList())));