2014-05-02 17 views
8

我想學習如何使用流的Java 8語法和有一點卡住的分組。的Java 8從一到多

這是很容易groupingBy當你擁有的每一個值一個關鍵。但是如果我爲每個值都有一個鍵列表並且仍然想用groupingBy對它們進行分類呢?我是否必須將其分成幾個陳述,或者是否有可能做一點小流魔術來使其更簡單。

這是基本的代碼:

List<Album> albums = new ArrayList<>(); 
Map<Artist, List<Album>> map = albums.stream().collect(Collectors.groupingBy(this::getArtist)); 

它的偉大工程,如果只有一個爲每張專輯的藝術家。但是我必須返回一個列表,因爲一個專輯可以有許多藝術家。專輯和藝術家用於課程的說明,我有真實世界的類型..

有可能是一個簡單的解決方案,但我還沒有發現它在一段時間,所以我呼籲集體大腦這個網站代表瞭解決這個問題。 :)如果不存在簡單的解決方案,也歡迎提供複雜的解決方案。

在Album類或者接受一個相冊作爲參數的實用方法:

Artist getArtist(); // ok 

List<Artist> getArtist(); // Not ok, since we now have many "keys" for every Album 

乾杯, 的Mikael GREV

+0

......有可能是一個簡單的解決方案:「羣星」 ;-) – mcalex

回答

13

我認爲你是Collectors.mapping可以作爲第二個參數傳遞後到groupingBy

完整示例

import java.util.AbstractMap; 
import java.util.List; 
import java.util.Map; 

import static java.util.Arrays.asList; 
import static java.util.Map.Entry; 
import static java.util.stream.Collectors.*; 

public class SO { 

    public static void main(String... args) { 

     List<Album> albums = asList(
       new Album(
         asList(
           new Artist("bob"), 
           new Artist("tom") 
         ) 
       ), 
       new Album(asList(new Artist("bill"))) 
     ); 

     Map<Artist, List<Album>> x = albums.stream() 
       .flatMap(album -> album.getArtist().stream().map(artist -> pair(artist, album))) 
       .collect(groupingBy(Entry::getKey, mapping(Entry::getValue, toList()))); 

     x.entrySet().stream().forEach(System.out::println); 
    } 

    static class Artist { 
     private final String name; 

     Artist(String name) { 
      this.name = name; 
     } 

     public String toString() {return name;} 

    } 

    static class Album { 
     private List<Artist> artist; 

     Album(List<Artist> artist) { 
      this.artist = artist; 
     } 

     List<Artist> getArtist() { 
      return artist; 
     } 

    } 

    private static <T,U> AbstractMap.SimpleEntry<T,U> pair(T t, U u) { 
     return new AbstractMap.SimpleEntry<T,U>(t,u); 
    } 


} 
+0

什麼令人印象深刻的速度! 看來工作(編譯最高審計機關確定,還不能運行,雖然由於重構。) 希望的是簡單的「包裝」的事情,但有時候事情,應該是簡單的不.. –

+0

我把它複製粘貼到Eclipse和我得到了編譯器錯誤:「類型不匹配:不能從地圖<對象,列出>轉換地圖>」。 –

0

如果有人正在尋找一個可行的例子,下面應該是有用的。

import java.util.AbstractMap; 
import java.util.AbstractMap.SimpleEntry; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 
import java.util.Map; 
import java.util.stream.Collectors; 

public class GroupSubject { 
    public static void main(String[] args) { 

     List<ContentItem> items = Arrays.asList(new ContentItem("maths"), new ContentItem("science"), 
       new ContentItem("social"), new ContentItem("chemistry"), new ContentItem("maths")); 

     Map<String, List<ContentItem>> x = (Map<String, List<ContentItem>>) items.stream() 
       .flatMap(item -> item.getSubjects().stream().map(subject -> pair(subject, item))) 
       .collect(Collectors.groupingBy(e -> ((SimpleEntry<String, ContentItem>) e).getKey(), Collectors 
         .mapping(e -> ((SimpleEntry<String, ContentItem>) e).getValue(), Collectors.toList()))); 

     System.out.println(x); 

    } 

    private static <T, U> AbstractMap.SimpleEntry<T, U> pair(T t, U u) { 
     return new AbstractMap.SimpleEntry<T, U>(t, u); 
    } 

} 

class ContentItem { 

    private List<String> subjects = new ArrayList<String>(); 

    public ContentItem(String string) { 
     subjects.add(string); 
    } 

    public List<String> getSubjects() { 
     return subjects; 
    } 

    public void setSubjects(List<String> subjects) { 
     this.subjects = subjects; 
    } 

} 
0

使用Guava's Multimap你可以有下面的代碼:

請注意,即使你有SetMultimap<Artist, Album>結果,這是相當於Map<Artist, List<Album>>所期望的結果。

我覺得這是一個有點清晰;)

SetMultimap<Artist, Album> artistToAlmbums = HashMultimap.create(); 
albums.stream().forEach(album -> { 
    album.getArtist().forEach(artist -> artistToAlmbums.put(artist, album)); 
});