將流拆分爲有序固定大小的塊(如Lists.partition
)是不可能的,因爲在並行執行中,每個塊將不得不等待其左空間塊被完全處理。
如果您不關心結果子地圖中按鍵的順序(因爲它將由Map#iterator
的方法返回),那麼您可以滾動自定義收集器。
private static <K, V> Collector<Map.Entry<K, V>, ?, List<Map<K, V>>> mapSize(int limit) {
return Collector.of(ArrayList::new,
(l, e) -> {
if (l.isEmpty() || l.get(l.size() - 1).size() == limit) {
l.add(new HashMap<>());
}
l.get(l.size() - 1).put(e.getKey(), e.getValue());
},
(l1, l2) -> {
if (l1.isEmpty()) {
return l2;
}
if (l2.isEmpty()) {
return l1;
}
if (l1.get(l1.size() - 1).size() < limit) {
Map<K, V> map = l1.get(l1.size() - 1);
ListIterator<Map<K, V>> mapsIte = l2.listIterator(l2.size());
while (mapsIte.hasPrevious() && map.size() < limit) {
Iterator<Map.Entry<K, V>> ite = mapsIte.previous().entrySet().iterator();
while (ite.hasNext() && map.size() < limit) {
Map.Entry<K, V> entry = ite.next();
map.put(entry.getKey(), entry.getValue());
ite.remove();
}
if (!ite.hasNext()) {
mapsIte.remove();
}
}
}
l1.addAll(l2);
return l1;
}
);
}
這一個將地圖項作爲值並將它們放入List<Map<K,V>>
。
累加器,檢查當前列表是否爲空或最後一個地圖的大小是否達到限制。如果是這樣的話,它會添加一個新的地圖。 然後,將當前所處理條目的新映射添加到地圖中。
組合器需要組合兩個並行構建的列表。如果其中一個列表爲空,則返回另一個列表。如果不是這種情況,則需要檢查第一個列表的最後一個地圖是否具有所需元素的數量。如果不是這種情況,我們抓住第二個列表的最後一個地圖,並且將元素添加到第一個列表的最後一個地圖。如果達到限制或者第二個列表中沒有更多要添加的元素,則停止。如果所有元素都被消耗掉,請不要忘記刪除空白地圖。
一種這樣的集電極的用法是:
List<Map<String, Set<String>>> listofMaps =
myMap.entrySet().stream().collect(mapSize(2));
一些實例(與兩個並行和串行流)與由13個鍵 - 值映射的初始地圖:
Size of maps 2
{11=[11a, 11b], 12=[12a, 12b]}
{13=[13b, 13a], 8=[8a, 8b]}
{1=[1a, 1b], 2=[2b, 2a]}
{3=[3a, 3b], 6=[6a, 6b]}
{4=[4a, 4b], 5=[5a, 5b]}
{7=[7a, 7b], 10=[10a, 10b]}
{9=[9a, 9b]}
=============================
Size of maps 5
{11=[11a, 11b], 12=[12a, 12b], 13=[13b, 13a], 6=[6a, 6b], 7=[7a, 7b]}
{1=[1a, 1b], 2=[2b, 2a], 3=[3a, 3b], 4=[4a, 4b], 5=[5a, 5b]}
{8=[8a, 8b], 9=[9a, 9b], 10=[10a, 10b]}
=============================
Size of maps 12
{11=[11a, 11b], 12=[12a, 12b], 1=[1a, 1b], 13=[13b, 13a], 2=[2b, 2a], 3=[3a, 3b], 4=[4a, 4b], 5=[5a, 5b], 6=[6a, 6b], 7=[7a, 7b], 8=[8a, 8b], 9=[9a, 9b]}
{10=[10a, 10b]}
=============================
Size of maps 15
{11=[11a, 11b], 12=[12a, 12b], 13=[13b, 13a], 1=[1a, 1b], 2=[2b, 2a], 3=[3a, 3b], 4=[4a, 4b], 5=[5a, 5b], 6=[6a, 6b], 7=[7a, 7b], 8=[8a, 8b], 9=[9a, 9b], 10=[10a, 10b]}
我沒有廣泛測試它。另外我認爲你可以修改它,使它更通用。
例如,您可能會接受任意對象,並使用兩個函數爲您正在處理的每個實例生成一個鍵和值。
private static <T, K, V> Collector<T, ?, List<Map<K, V>>> mapSize(Function<T, K> keyFunc, Function<T, V> mapFunc, int limit) {
與
l.get(l.size() - 1).put(keyFunc.apply(e), mapFunc.apply(e));
,並調用它像:
.collect(mapSize(Map.Entry::getKey, Map.Entry::getValue, size));
沒有什麼特別。這不是那種容易(甚至根本不能)用Java 8流表達的操作。 –
如果你指的是番石榴的'Lists.partition',這是一個可行的方法,可能與Java 8結合使用,儘管你可以使用'Iterables.partition'來代替。 –