Można użyć IntStream.iterate
połączeniu z toMap
kolektora i sposobu subList
na List
(dzięki Duncan dla uproszczenia).
import static java.util.stream.Collectors.toMap;
import static java.lang.Math.min;
...
static Map<Integer, List<Integer>> partition(List<Integer> list, int pageSize) {
return IntStream.iterate(0, i -> i + pageSize)
.limit((list.size() + pageSize - 1)/pageSize)
.boxed()
.collect(toMap(i -> i/pageSize,
i -> list.subList(i, min(i + pageSize, list.size()))));
}
Najpierw należy obliczyć liczbę kluczy potrzebnych na mapie. Jest to podane przez (list.size() + pageSize - 1)/pageSize
(będzie to limit strumienia).
Następnie tworzysz strumień, który tworzy sekwencję 0, pageSize, 2* pageSize, ...
.
Teraz dla każdej wartości i
chwycić odpowiedni subList
który będzie nasza wartość (trzeba dodatkowy czek na ostatniej subList
nie otrzymania poza granicami), dla którego mapa odpowiedni klawisz, który będzie sekwencja 0/pageSize, pageSize/pageSize, 2*pageSize/pageSize
że dzielisz przez pageSize
, aby uzyskać naturalną sekwencję 0, 1, 2, ...
.
Rurociąg może być bezpiecznie uruchomiony równolegle (może być konieczne użycie kolektora toConcurrentMap
). Jak skomentował Brian Goetz (dzięki za przypomnienie mi, że tak), iterate
nie jest warta, jeśli chcesz zrównoleglić strumień, więc tutaj jest wersja z range
.
return IntStream.range(0, (list.size() + pageSize - 1)/pageSize)
.boxed()
.collect(toMap(i -> i ,
i -> list.subList(i * pageSize, min(pageSize * (i + 1), list.size()))));
Tak jak z przykładu (lista 10 elementów o rozmiarze stronie 3), otrzymasz następującą sekwencję:
0, 3, 6, 9, 12, 15, ...
że można ograniczyć do (10 + 3 - 1)/3 = 12/3 = 4
, które pozwalają sekwencja 0, 3, 6, 9
. Teraz każda wartość jest mapowany do jego odpowiedniego podmenu:
0/pageSize = 0 -> list.subList(0, min(0 + pageSize, 10)) = list.subList(0, 3);
3/pageSize = 1 -> list.subList(3, min(3 + pageSize, 10)) = list.subList(3, 6);
6/pageSize = 2 -> list.subList(6, min(6 + pageSize, 10)) = list.subList(6, 9);
9/pageSize = 3 -> list.subList(9, min(9 + pageSize, 10)) = list.subList(6, 10);
^
|
this is the edge-case for the last sublist to
not be out of bounds
Jeśli naprawdę chcesz
Map<Integer, String>
można zastąpić funkcję wartość odwzorowujący z
import static java.util.stream.Collectors.joining;
...
i -> list.subList(i, min(i + pageSize, list.size()))
.stream()
.map(Object::toString)
.collect(joining(","))
które po prostu zebrać elementy oddzielone przecinkiem w pojedynczy ciąg.
Co próbowałeś do tej pory? Przeczytaj [Jak zadać dobre pytanie?] (Http://stackoverflow.com/help/how-to-ask). – DavidPostill
Tak więc zajrzałem do Collectors :: partitioningBy, ale to dzieli listę z danym predykatem. Zapytałem o to, ponieważ nie wiem, od czego zacząć w Javie 8, aby to osiągnąć. – adragomir
@ user3030447 Czy jesteś pewien, że chcesz 'Map' a nie 'Map >'? Zawsze możesz przekonwertować listę na ciąg znaków w fazie prezentacji ... –