Thu thập kết quả của thao tác bản đồ trong Bản đồ bằng Collector.toMap hoặc groupingBy


8

Tôi đã có một danh sách loại List<A>và với thao tác bản đồ nhận danh sách loại chung List<B>cho tất cả các thành phần A được hợp nhất trong một danh sách.

List<A> listofA = [A1, A2, A3, A4, A5, ...]

List<B> listofB = listofA.stream()
  .map(a -> repo.getListofB(a))
  .flatMap(Collection::stream)
  .collect(Collectors.toList());

không có bản đồ

List<List<B>> listOflistofB = listofA.stream()
  .map(a -> repo.getListofB(a))
  .collect(Collectors.toList());

Tôi muốn thu thập các kết quả dưới dạng bản đồ loại Map<A, List<B>>và cho đến nay đã thử với nhiều tùy chọn Collectors.toMaphoặc Collectors.groupingBytùy chọn khác nhau nhưng không thể có được kết quả mong muốn.


2
Bạn có Acác yếu tố lặp đi lặp lại trong của bạn List<A>?
Federico Peralta Schaffner

Câu trả lời:


8

Bạn có thể sử dụng trình toMapthu thập với tham chiếu phương thức giới hạn để có được những gì bạn cần. Cũng lưu ý rằng giải pháp này giả định rằng bạn không lặp lại một thể hiện trong thùng chứa nguồn của mình. Nếu điều kiện tiên quyết đó giữ giải pháp này sẽ cho bạn kết quả mong muốn. Đây là vẻ ngoài của nó.

Map<A, Collection<B>> resultMap = listofA.stream()
    .collect(Collectors.toMap(Function.identity(), repo::getListofB);

Nếu bạn có các phần tử A trùng lặp, thì bạn phải sử dụng hàm hợp nhất này ngoài các phần tử được đưa ra ở trên. Hàm hợp nhất xử lý các xung đột chính nếu có.

Map<A, Collection<B>> resultMap = listofA.stream()
       .collect(Collectors.toMap(Function.identity(), repo::getListofB, 
            (a, b) -> {
                a.addAll(b);
                return a;
        }));

Và đây là một cách tiếp cận Java9 ngắn gọn hơn, sử dụng trình flatMappingthu thập để xử lý các phần tử A lặp đi lặp lại.

Map<A, List<B>> aToBmap = listofA.stream()
        .collect(Collectors.groupingBy(Function.identity(),
                Collectors.flatMapping(a -> getListofB(a).stream(), 
                        Collectors.toList())));

2
Xin chào, bạn đã thêm cách xử lý các bản sao! Tôi đã thêm một câu trả lời với điều đó, tôi sẽ để nó bởi vì tôi nghĩ rằng nó bổ sung cho bạn, chúc mừng!
Federico Peralta Schaffner

2
Vâng, bình luận của bạn rất hữu ích. Nắm bắt tốt !
Ravindra Ranwala

3

Nó sẽ là thẳng về phía trước,

listofA.stream().collect(toMap(Function.identity(), a -> getListofB(a)));

2

Để thu thập Mapcác khóa trong đó các Ađối tượng là các đối tượng không thay đổi và các giá trị là danh sách các Bđối tượng tương ứng , bạn có thể thay thế trình toList()thu thập bằng trình thu thập sau:

toMap(Function.identity(), a -> repo.getListOfB(a))

Đối số đầu tiên xác định cách tính khóa từ đối tượng ban đầu: identity()lấy đối tượng gốc của luồng không thay đổi.

Đối số thứ hai xác định cách tính giá trị , vì vậy ở đây nó chỉ bao gồm một lệnh gọi phương thức của bạn để chuyển đổi Amột danh sách B.

repophương thức chỉ mất một tham số, bạn cũng có thể cải thiện độ rõ bằng cách thay thế lambda bằng tham chiếu phương thức:

toMap(Function.identity(), repo::getListOfB)

Cảm ơn @kgautron, câu trả lời của bạn là chính xác và được giải thích rõ ràng. Tôi chấp nhận câu trả lời khác vì tôi thấy nó đầu tiên.
Amitoj

2

Trong câu trả lời này, tôi sẽ chỉ ra điều gì xảy ra nếu bạn có Acác yếu tố lặp lại trong List<A> listofAdanh sách của mình .

Trên thực tế, nếu có các bản sao trong listofA, đoạn mã sau sẽ đưa ra IllegalStateException:

Map<A, Collection<B>> resultMap = listofA.stream()
        .collect(Collectors.toMap(
                            Function.identity(), 
                            repo::getListofB);

Ngoại lệ có thể bị ném vì Collectors.toMapkhông biết cách hợp nhất các giá trị khi có xung đột trong các khóa (nghĩa là khi chức năng ánh xạ khóa trả về các bản sao, vì đó sẽ là trường hợp Function.identity()nếu có các phần tử lặp lại trong listofAdanh sách).

Điều này được nêu rõ trong các tài liệu :

Nếu các khóa được ánh xạ chứa các bản sao (theo Object.equals(Object)), một khóa IllegalStateExceptionsẽ được ném khi thao tác thu thập được thực hiện. Nếu các phím được ánh xạ có thể có trùng lặp, sử dụng toMap(Function, Function, BinaryOperator) thay vào đó.

Các tài liệu cũng cung cấp cho chúng tôi giải pháp: trong trường hợp có các yếu tố lặp lại, chúng tôi cần cung cấp một cách để hợp nhất các giá trị. Đây là một cách như vậy:

Map<A, Collection<B>> resultMap = listofA.stream()
        .collect(Collectors.toMap(
                            Function.identity(), 
                            a -> new ArrayList<>(repo.getListofB(a)),
                            (left, right) -> {
                                left.addAll(right);
                                return left;
                            });

Điều này sử dụng phiên bản quá tải của Collectors.toMapchấp nhận hàm hợp nhất làm đối số thứ ba của nó. Trong hàm hợp nhất, Collection.addAllđang được sử dụng để thêm các Bphần tử của mỗi Aphần tử lặp lại vào danh sách unueue cho mỗi phần tử A.

Trong hàm ánh xạ giá trị, một cái mới ArrayListđược tạo ra, sao cho bản gốc List<B>của mỗi cái Akhông bị đột biến. Ngoài ra, khi chúng tôi tạo một Arraylist, chúng tôi biết trước rằng nó có thể bị đột biến (nghĩa là chúng tôi có thể thêm các yếu tố vào sau, trong trường hợp có các bản sao trong listofA).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.