2016-06-22 90 views
1

我想我得到在Java的8流還不錯,但後來地圖...Java流收集與多個鍵

我有一個Foo接口:

public interface Foo { 
    String getKey(); 
    Stream<Bar> bars(); 
} 

我知道我可以收集一個Stream<Foo>Map<String, Foo>使用每個鍵:

Map<String, Foo> foosByKey = fooStream.collect(
    Collectors.toMap(Foo::getKey, Function.identity())); 

但是如果我想將其收集到Map<Bar, Foo>?換句話說,對於蒸汽中的每個Foo,我想要將那個Foo放在映射中,以便鍵入由Foo.bars()返回的每個Bar實例。我從哪說起呢?

+0

不,你有它倒退。 'Map '意味着'Bar'和'Foo'實例之間的一對一映射。考慮一下'Map '或'Map ',一個人可以有多張信用卡,一本書可以有多個ISBN。沒有什麼複雜的。 –

+0

我確實明白這個意思,但我不想掛在有點附屬的點上。映射是否爲雙向取決於圖是否是方向性的。一個Java'Map'是一個單向的,所以你不能映射回---這就是爲什麼Guava有一個'BiMap'的原因。我想你想說的是_relationship_是一對一的 - 在這種情況下,_relationship_是多對一的('Bar'-'Foo')。但這又是一個問題 - 就啤酒辯論的問題。總結就是每個'Foo'都可以有很多'Bar',我想把'Bar'映射到'Foo'。乾杯! –

+0

事實上,我們可以通過聲明來說明每個'Foo'可以有很多'Bar'並且所有'Bar'都是不同的,我想[Sotirios'answer](http://stackoverflow.com/a/37956805/2711488)包含適當的解決方案。有沒有什麼能阻止你接受他的答案,我們應該解決? – Holger

回答

2

如建議here,您需要從每個Foo中提取Bar值並創建它們的對。一旦你有了這兩對,你可以將它們收集到一個Map。例如,

Map<Bar, Foo> map = fooStream.flatMap(foo -> foo.bars().map(bar -> new SimpleEntry<>(bar, foo))) 
      .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); 

我們使用SimpleEntry這裏,因爲它是可用的(Java沒有一個簡單的Pair型)。你可以自己寫更具體的。

+1

'SimpleEntry <>'的使用很酷---我沒有意識到Java有一些東西至少與'Pair'類似。總的來說,雖然我希望能有一些更緊湊的東西,但這可能是我們能得到的最好的。我會離開它一段時間,看看我們是否有其他選擇。 –

+1

Java 9將增加使用'Map.entry(bar,foo)'以更簡潔的方式構造基於值的不可變條目的可能性。 – Holger