Transforming/GroupingBy 列表中的值
Transforming/GroupingBy values inside List
给定
List<Student>
其中每个 Student
有 List<Book>
,按 Book
分组 List<Student>
工作解决方案(使用 Java 9)
我已经有下面提到的工作代码
public class Demo {
public static void main(String[] args) {
List<Student> studs = createStudents();
var data = studs.stream()
.flatMap(s -> s.getBooks()
.stream()
.map(b -> Pair.of(b, s))) // <------ is possible without using external class?
.collect(Collectors.groupingBy(
p -> p.getBook(),
Collectors.mapping(p -> p.getStud().getFirstName(), Collectors.toList())));
System.out.println("All books: " + data);
}
private static List<Student> createStudents() {
Book javaCompleteReference = new Book("Java Complete Reference");
Book ocjp = new Book("Java OCJP");
Book sql = new Book("SQL");
Book spring = new Book("SPRING in Action");
return List.of(
new Student(1, "A", List.of(javaCompleteReference, spring)),
new Student(2, "B", List.of(spring, sql, ocjp)),
new Student(3, "C", List.of(javaCompleteReference, sql))
);
}
}
正在寻找:
- 我使用了 flatMap 和中间 class 对。是否可以使用 Pair class
不使用中间转换来实现最终结果
代码库:
public class Book {
private String title;
private String id;
private Integer pages;
public Book(String title, String id, Integer pages) {
this.title = title;
this.id = id;
this.pages = pages;
}
public Book(String title) { this.title = title; }
public String getTitle() { return title; }
public String getId() { return id; }
public Integer getPages() { return pages; }
@Override
public String toString() { return title; }
}
class Pair {
Book book;
Student stud;
private Pair(Book book, Student stud) {
this.book = book;
this.stud = stud;
}
static Pair of(Book book, Student stud) { return new Pair(book, stud); }
public Book getBook() { return book; }
public Student getStud() { return stud; }
}
public class Student {
private Integer id;
private String firstName;
private List<Book> books;
public Student(Integer id, String firstName, List<Book> books) {
this.id = id;
this.firstName = firstName;
this.books = books;
}
public Integer getId() { return id; }
public String getFirstName() { return firstName; }
public List<Book> getBooks() { return books; }
}
输出:All books: {Java Complete Reference=[A, C], SQL=[B, C], SPRING in Action=[A, B], Java OCJP=[B]}
is possible without using external class?
是的,甚至在 java 的早期版本中也是可能的。只需使用 AbstractMap.SimpleEntry<K, V>
代替:
.map(b -> new AbstractMap.SimpleEntry<>(b, s)))
然后您可以通过调用 getKey()
和 getValue()
来访问这些值。
这 不可能 使用 Stream API 只要您需要保留 both 关于学生姓名的信息和 上下文中的每个 Book 以形成一个输出映射。平面映射到单个元素(对)是唯一可行的方法。
一个证明和替代(我想不是更好)解决方案是使用 Collectors.flatMapping
和 Collectors.toMap
的组合,您可以在其中定义所有 keyMapper
、valueMapper
和mergeFunction
。你可以清楚地看到,在Collectors.grouping
中,你需要组合所有Student的名字和每个Book的关系。
var data = studs.stream().collect(Collectors.flatMapping(
student -> student.getBooks()
.stream()
.map(book -> new AbstractMap.SimpleEntry<>(
student.getFirstName(), book)),
Collectors.toMap(
AbstractMap.SimpleEntry::getValue,
entry -> new ArrayList<>(List.of(entry.getKey())),
(leftList, rightList) -> { leftList.addAll(rightList); return leftList; })));
给定
List<Student>
其中每个 Student
有 List<Book>
,按 Book
分组 List<Student>
工作解决方案(使用 Java 9) 我已经有下面提到的工作代码
public class Demo {
public static void main(String[] args) {
List<Student> studs = createStudents();
var data = studs.stream()
.flatMap(s -> s.getBooks()
.stream()
.map(b -> Pair.of(b, s))) // <------ is possible without using external class?
.collect(Collectors.groupingBy(
p -> p.getBook(),
Collectors.mapping(p -> p.getStud().getFirstName(), Collectors.toList())));
System.out.println("All books: " + data);
}
private static List<Student> createStudents() {
Book javaCompleteReference = new Book("Java Complete Reference");
Book ocjp = new Book("Java OCJP");
Book sql = new Book("SQL");
Book spring = new Book("SPRING in Action");
return List.of(
new Student(1, "A", List.of(javaCompleteReference, spring)),
new Student(2, "B", List.of(spring, sql, ocjp)),
new Student(3, "C", List.of(javaCompleteReference, sql))
);
}
}
正在寻找:
- 我使用了 flatMap 和中间 class 对。是否可以使用 Pair class 不使用中间转换来实现最终结果
代码库:
public class Book {
private String title;
private String id;
private Integer pages;
public Book(String title, String id, Integer pages) {
this.title = title;
this.id = id;
this.pages = pages;
}
public Book(String title) { this.title = title; }
public String getTitle() { return title; }
public String getId() { return id; }
public Integer getPages() { return pages; }
@Override
public String toString() { return title; }
}
class Pair {
Book book;
Student stud;
private Pair(Book book, Student stud) {
this.book = book;
this.stud = stud;
}
static Pair of(Book book, Student stud) { return new Pair(book, stud); }
public Book getBook() { return book; }
public Student getStud() { return stud; }
}
public class Student {
private Integer id;
private String firstName;
private List<Book> books;
public Student(Integer id, String firstName, List<Book> books) {
this.id = id;
this.firstName = firstName;
this.books = books;
}
public Integer getId() { return id; }
public String getFirstName() { return firstName; }
public List<Book> getBooks() { return books; }
}
输出:All books: {Java Complete Reference=[A, C], SQL=[B, C], SPRING in Action=[A, B], Java OCJP=[B]}
is possible without using external class?
是的,甚至在 java 的早期版本中也是可能的。只需使用 AbstractMap.SimpleEntry<K, V>
代替:
.map(b -> new AbstractMap.SimpleEntry<>(b, s)))
然后您可以通过调用 getKey()
和 getValue()
来访问这些值。
这 不可能 使用 Stream API 只要您需要保留 both 关于学生姓名的信息和 上下文中的每个 Book 以形成一个输出映射。平面映射到单个元素(对)是唯一可行的方法。
一个证明和替代(我想不是更好)解决方案是使用 Collectors.flatMapping
和 Collectors.toMap
的组合,您可以在其中定义所有 keyMapper
、valueMapper
和mergeFunction
。你可以清楚地看到,在Collectors.grouping
中,你需要组合所有Student的名字和每个Book的关系。
var data = studs.stream().collect(Collectors.flatMapping(
student -> student.getBooks()
.stream()
.map(book -> new AbstractMap.SimpleEntry<>(
student.getFirstName(), book)),
Collectors.toMap(
AbstractMap.SimpleEntry::getValue,
entry -> new ArrayList<>(List.of(entry.getKey())),
(leftList, rightList) -> { leftList.addAll(rightList); return leftList; })));