2016-04-06 33 views
5

Tôi có một cái gì đó giống như dưới đây:nhóm đối tượng java 8

public class MyClass { 
private Long stackId 
private Long questionId 
} 

Một bộ sưu tập của nói 100, nơi stackid có thể trùng lặp với questionIds khác nhau. một của nó đối với nhiều mối quan hệ giữa stackId và questionId

nước chảy, java 8 cách để chuyển sang strcuture dưới đây:

public class MyOtherClass { 
private Long stackId 
private Collection<Long> questionIds 
} 

Đó sẽ là một bộ sưu tập 25, với mỗi trường hợp có một bộ sưu tập lồng nhau gồm 4 câu hỏi.

Input:

[{1,100},{1,101},{1,102},{1,103},{2,200},{2,201},{2,202},{1,203}] 

Output

[{1, [100,101,102,103]},{2,[200,201,202,203]}] 
+2

http: //www.markhneedham.com/blog/2014/02/23/java-8-nhóm-by-với-bộ sưu tập/- chuyển đổi thành một 'Bản đồ >' trước tiên, sau đó chuyển đổi các mục của bản đồ đó thành (loại thứ hai) 'MyClass' trường hợp. –

+1

Tôi vẫn không hiểu * Đó sẽ là một bộ sưu tập 25, * một phần. Bạn có thể mở rộng không? Bạn có muốn bộ sưu tập chứa tối đa 25 phần tử không? Chúng ta sẽ làm gì với phần còn lại? – Tunaki

+0

@Tunaki đầu ra có ít phần tử gốc hơn đầu vào, nhưng sau đó mỗi phần tử gốc có mối quan hệ một đến nhiều với các phần tử con (questionIds) – NimChimpsky

Trả lời

9

Cách thẳng về phía trước với các API Suối bao gồm 2 đường ống Suối:

  • Người đầu tiên tạo ra một tạm thời Map<Long, List<Long>> của stackId đến questionIds. Điều này được thực hiện với các bộ thu groupingBy(classifier, downstream) mà chúng tôi phân loại theo số stackId và các giá trị có cùng một stackId được ánh xạ tới questionId (với mapping) và được thu thập vào danh sách có toList().
  • Cái thứ hai chuyển đổi mỗi mục nhập của bản đồ đó thành một cá thể MyOtherClass và thu thập nó vào một danh sách.

Giả sử bạn có một constructor MyOtherClass(Long stackId, Collection<Long> questionIds), một mẫu mã sẽ là:

Map<Long, List<Long>> map = 
    list.stream() 
     .collect(Collectors.groupingBy(
      MyClass::getStackId, 
      Collectors.mapping(MyClass::getQuestionId, Collectors.toList()) 
     )); 

List<MyOtherClass> result = 
    map.entrySet() 
     .stream() 
     .map(e -> new MyOtherClass(e.getKey(), e.getValue())) 
     .collect(Collectors.toList()); 

Sử dụng StreamEx thư viện, bạn có thể làm điều đó trong một đường ống dẫn Suối duy nhất. Thư viện này cung cấp một bộ sưu tập pairingfirst. Điều này cho phép ghép hai nhà sưu tập và thực hiện một thao tác dứt điểm trên hai kết quả thu được:

  • Người đầu tiên chỉ giữ stackId đầu tiên của các yếu tố nhóm (tất cả họ sẽ giống nhau, bởi xây dựng)
  • Các thứ hai ánh xạ từng phần tử vào questionId của chúng và thu thập vào danh sách.
  • Thao tác hoàn tất chỉ trả lại phiên bản mới MyOtherClass.

Mẫu mã:

import static java.util.stream.Collectors.collectingAndThen; 
import static java.util.stream.Collectors.mapping; 
import static java.util.stream.Collectors.toList; 
import static one.util.streamex.MoreCollectors.first; 
import static one.util.streamex.MoreCollectors.pairing; 

// ... 

Collection<MyOtherClass> result = 
    StreamEx.of(list) 
      .groupingBy(
       MyClass::getStackId, 
       pairing(
        collectingAndThen(mapping(MyClass::getStackId, first()), Optional::get), 
        mapping(MyClass::getQuestionId, toList()), 
        MyOtherClass::new 
       ) 
      ).values(); 
+0

Wow cảm ơn vì câu trả lời sâu sắc. Bạn đã sử dụng bất kỳ libs functinal nào khác chưa? https://github.com/akullpp/awesome-java#functional-programming. Điều này http://www.javaslang.io/ trông particualy hoạt động/đánh bóng. – NimChimpsky

+1

@NimChimpsky Không, tôi chưa bao giờ sử dụng chúng (một chút xíu). – Tunaki

2
List<MyClass> inputs = Arrays.asList(
    new MyClass(1L, 100L), 
    new MyClass(1L, 101L), 
    new MyClass(1L, 102L), 
    new MyClass(1L, 103L), 
    new MyClass(2L, 200L), 
    new MyClass(2L, 201L), 
    new MyClass(2L, 202L), 
    new MyClass(2L, 203L) 
); 

Map<Long, List<Long>> result = inputs 
    .stream() 
    .collect(
     Collectors.groupingBy(MyClass::getStackId, 
     Collectors.mapping(
      MyClass::getQuestionId, 
      Collectors.toList() 
     ) 
    ) 
    ); 
0

Bạn có thể sử dụng các nhà sưu tập java8 groupingBy. Như thế này:

import org.junit.Test; 

import java.util.ArrayList; 
import java.util.List; 
import java.util.Set; 
import java.util.stream.Collectors; 

public class RandomTest { 

    class MyClass { 
     private Long stackId; 
     private Long questionId; 

     public MyClass(Long stackId, Long questionId) { 
      this.stackId = stackId; 
      this.questionId = questionId; 
     } 

     public Long getStackId() { 
      return stackId; 
     } 

     public Long getQuestionId() { 
      return questionId; 
     } 
    } 

    public class MyOtherClass { 
     private Long stackId; 
     private Set<Long> questionIds; 

     public MyOtherClass(Long stackId, Set<Long> questionIds) { 
      this.stackId = stackId; 
      this.questionIds = questionIds; 
     } 

     public Long getStackId() { 
      return stackId; 
     } 

     public Set<Long> getQuestionIds() { 
      return questionIds; 
     } 
    } 

    @Test 
    public void test() { 
     List<MyClass> classes = new ArrayList<>(); 
     List<MyOtherClass> otherClasses = new ArrayList<>(); 

     //populate the classes list 
     for (int j = 1; j <= 25; j++) { 
      for (int i = 0; i < 4; i++) { 
       classes.add(new MyClass(0L + j, (100L*j) + i)); 
      } 
     } 

     //populate the otherClasses List 
     classes.stream().collect(Collectors 
       .groupingBy(MyClass::getStackId, Collectors.mapping(MyClass::getQuestionId, Collectors.toSet()))) 
       .entrySet().stream().forEach(
       longSetEntry -> otherClasses.add(new MyOtherClass(longSetEntry.getKey(), longSetEntry.getValue()))); 

     //print the otherClasses list 
     otherClasses.forEach(myOtherClass -> { 
      System.out.print(myOtherClass.getStackId() + ": ["); 
      myOtherClass.getQuestionIds().forEach(questionId-> System.out.print(questionId + ",")); 
      System.out.println("]"); 
     }); 
    } 
} 
Các vấn đề liên quan