2016-04-06 40 views
5

我有類似下面的:說100,其中stackid可重複使用不同questionIds的分組對象的Java 8

public class MyClass { 
private Long stackId 
private Long questionId 
} 

的集合。它一到stackId和questionId

之間一對多的關係是否有轉換到下面的晶格結構一個流j,JAVA 8路:

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

這將是25集,具有每個實例4個questionIds的嵌套集合。

輸入:

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

輸出

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

http://www.markhneedham。com/blog/2014/02/23/java-8-group-by-with-collections/- 先轉換成Map >,然後將該地圖的條目轉換爲(第二種)'MyClass'實例。 –

+1

我還是不明白*哪一個是25,*部分的集合。你能擴展嗎?你想收藏最多包含25個元素?我們應該怎麼辦? – Tunaki

+0

@Tunaki輸出具有比輸入更少的根元素,但是每個根元素與子元素(questionIds)有一對多的關係 – NimChimpsky

回答

9

與流API的直接的方式涉及2個管道:

  • 第一個創建臨時的stackIdquestionIds。這是通過groupingBy(classifier, downstream)收集器完成的,其中我們根據stackId進行分類,並將具有相同stackId的值映射到它們的questionId(與mapping)並且收集到與toList()一起的列表中。
  • 第二個將該地圖的每個條目轉換爲MyOtherClass實例並將其收集到列表中。

假設你有一個構造函數MyOtherClass(Long stackId, Collection<Long> questionIds),樣本代碼將是:

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()); 

使用StreamEx庫,你可以做,在一個單一的Stream天然氣管道。該圖書館提供pairingfirst收藏家。這使得能夠對的兩個收集器和在兩個收集的結果執行裝訂操作:

  • 第一個只保存分組元素的第一stackId(它們都將是相同的,由結構)
  • 的第二個將每個元素映射到它們的questionId並收集到一個列表中。
  • 修整器操作僅返回MyOtherClass的新實例。

示例代碼:

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

謝謝你的深入答案。你有沒有使用任何其他函數庫? https://github.com/akullpp/awesome-java#functional-programming。這http://www.javaslang.io/看起來特別活躍/拋光。 – NimChimpsky

+1

@NimChimpsky不,我從來沒有使用過這些(有點jOOL)。 – 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

可以使用java8 groupingBy收集器。像這樣:

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("]"); 
     }); 
    } 
}