我有像
这样的对象结构class Person{
String userId;
String firstName;
String lastName;
Set<Courses> courses = new HashSet<Courses>();
}
数据库记录是这样的(实际上用户firstName和lastName来自另一个表,但为了简单起见,我将如下所示):
user1 John Smith course1
user1 John Smith course2
user1 John Smith course3
user2 Jack Smith course1
user2 Jack Smith course2
从数据库中检索结果到List<Map<String, Object>> resultSet
。
现在我需要按userId进行分组,然后将课程映射到Set并创建List<Person>
个对象。
现在我可以按userId进行分组并将课程收集到集合中但不能映射firstName和lastName。
Map<Object, Set<Object>> userList = resultSet.stream().collect()
.Collectors.groupingBy( usr -> usr.get("user_id"),
Collectors.mapping( usr -> usr.get("courses"), Collectors.toSet()) ));
// Result {user1=[course1, course2, course3]}
然后我正在创建Person Object
List<Person> = userList.entrySet.stream().
.map( usr -> new Person(usr.getKey().toString(),
(Set<Courses)(Set<?>)usr.getValue()))
.collect(Collectors.toList())
如何在groupingby步骤中获取firstName,lastName并使用它来创建对象?
答案 0 :(得分:4)
您可以使用Collectors.toMap
代替Collectors.groupingBy
。您将通过传递给toMap
的合并函数实现分组。
它会创建一些不必要的Person
实例,但最终结果将包含您想要的内容。
Map<String,Person> persons =
resultSet.stream()
.collect(Collectors.toMap(usr -> usr.get("user_id"),
usr -> new Person(usr.get("user_id"),usr.get("first_name"),usr.get("last_name"),usr.get("course")),
(p1,p2)->{p1.addCourses(p2.getCourses()); return p1;}));
假设您在Person
类中有相关的构造函数和方法。
答案 1 :(得分:2)
您还可以尝试将作为下游功能传递的自定义收集器定义为Collectors.groupingBy()
。请考虑以下示例:
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collector;
import java.util.stream.Collectors;
public class PersonGroupByExample {
public static void main(String[] args) {
final List<Map<String, Object>> input = Arrays.asList(
new HashMap<String, Object>(){{
put("userId", "user1");
put("firstName", "John");
put("lastName", "Smith");
put("courses", "course1");
}},
new HashMap<String, Object>(){{
put("userId", "user1");
put("firstName", "John");
put("lastName", "Smith");
put("courses", "course2");
}},
new HashMap<String, Object>(){{
put("userId", "user1");
put("firstName", "John");
put("lastName", "Smith");
put("courses", "course3");
}},
new HashMap<String, Object>(){{
put("userId", "user2");
put("firstName", "Jack");
put("lastName", "Smith");
put("courses", "course1");
}},
new HashMap<String, Object>(){{
put("userId", "user2");
put("firstName", "Jack");
put("lastName", "Smith");
put("courses", "course2");
}}
);
final Collection<Person> result = input.stream()
.parallel()
.collect(Collectors.groupingBy(it -> it.get("userId"), Collector.of(
// Start with an empty Person object
Person::new,
// Collect a list of map objects grouped by the same userId into a single Person object
(person, map) -> {
// Override common properties
person.setUserId(map.getOrDefault("userId", "").toString());
person.setFirstName(map.getOrDefault("firstName", "").toString());
person.setLastName(map.getOrDefault("lastName", "").toString());
// Add person's course to a courses set
person.getCourses().add(new Course(map.getOrDefault("courses", "").toString()));
},
// Combiner function that join partials results (for parallel execution)
(person, person2) -> {
person.getCourses().addAll(person2.getCourses());
return person;
}
))).values();
result.forEach(System.out::println);
}
static class Person {
String userId;
String firstName;
String lastName;
Set<Course> courses = new HashSet<>();
public Person() {}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Set<Course> getCourses() {
return courses;
}
public void setCourses(Set<Course> courses) {
this.courses = courses;
}
@Override
public String toString() {
return "Person{" +
"userId='" + userId + '\'' +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", courses=" + courses +
'}';
}
}
static class Course {
String id;
public Course(String id) {
this.id = id;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public String toString() {
return "Course{" +
"id='" + id + '\'' +
'}';
}
}
}
Collectors.groupingBy()
按userId
字段对所有条目进行分组,然后具有自定义收集器的下游函数将按Map<String, Object>
分组的userId
条目列表减少为单个{{ 1}}包含所有课程的实例。我使用Person
和Person
POJO只是为了说明流程,输入Course
也用作转换过程的说明。
最后,我们调用List<Map<String, Object>>
方法返回Map.values()
而不是Collection<Person>
。
运行此示例将创建以下输出:
Map<String, Person>
答案 2 :(得分:0)
你应该使用减少。
这个想法是使用一个具有单courses
集的Person对象映射每一行,然后分组并减少。
Map<String, Person> people = userList = resultSet.stream()
.map(v -> toPerson())
.collect(groupingBy(Person::getId, reducing(null, (p1, p2) -> {
p1.getCourses().addAll(p2.getCourses);
return p1;
})));
希望你明白这一点。