Comment paginer une liste D'objets en Java 8?
avec un java.util.List
n
et la page désirée taille m
, je veux le transformer en une carte contenant n/m+n%m
éléments. Chaque élément de la carte doit contenir m
éléments.
Voici un exemple avec des entiers:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// What is the equivalent Java 8 code to create the map below from my list?
Map<Integer, List<Integer>> map = new HashMap<>();
map.put(0, Arrays.asList(1,2,3));
map.put(1, Arrays.asList(4,5,6));
map.put(2, Arrays.asList(7,8,9));
map.put(3, Arrays.asList(10));
est-ce possible, en utilisant Java 8?
3 réponses
Vous pouvez utiliser IntStream.iterate
combiné avec le toMap
collecteur et le subList
méthode List
(merci à Duncan pour les simplifications).
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()))));
}
vous calculez d'abord le nombre de touches dont vous avez besoin dans la carte. Ceci est donné par (list.size() + pageSize - 1) / pageSize
(ce sera la limite du flux).
puis vous créez un flux qui crée la séquence 0, pageSize, 2* pageSize, ...
.
Maintenant, pour chaque valeur i
vous attrapez lesubList
qui sera notre valeur (vous avez besoin d'un contrôle supplémentaire pour la dernière subList
pour ne pas sortir des limites du terrain) pour lequel vous carte la touche correspondante qui sera la séquence 0/pageSize, pageSize/pageSize, 2*pageSize/pageSize
que vous divisez par pageSize
pour obtenir la séquence naturelle 0, 1, 2, ...
.
Le pipeline peut être en toute sécurité exécuter en parallèle (vous devrez peut-être utiliser le toConcurrentMap
collecteur à la place). Comme L'a dit Brian Goetz (merci de me le rappeler),iterate
n'est pas la peine si vous voulez paralléliser le flux, donc voici un version avec 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()))));
comme avec votre exemple (une liste de 10 éléments avec une page de 3), vous obtiendrez la séquence suivante:
0, 3, 6, 9, 12, 15, ...
que vous limitez à (10 + 3 - 1) / 3 = 12 / 3 = 4
, qui laissent la séquence 0, 3, 6, 9
. Maintenant chaque valeur est mappée à sa sous-liste correspondante:
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
Si vous voulez vraiment un
Map<Integer, String>
vous pouvez remplacer la fonction value mapper par
import static java.util.stream.Collectors.joining;
...
i -> list.subList(i, min(i + pageSize, list.size()))
.stream()
.map(Object::toString)
.collect(joining(","))
qui vient de recueillir les éléments séparés par une virgule dans une seule Chaîne.
solution Simple à l'aide de Goyave: com.Google.commun.recueillir.Les listes#partition:
List<List<Integer>> partition = Lists.partition(list, 3); //<- here
Map map = IntStream.range(0, partition.size()).boxed().collect(Collectors.toMap(
Function.identity(),
i -> partition.get(i)));
comme noté dans les commentaires cela fonctionne aussi si la liste n'est pas une séquence naturelle d'entiers. Vous auriez à utiliser une générés IntStream
puis et référez-vous aux éléments dans list by index.
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Map<Integer, String> map = IntStream
.range(0, list.size())
.boxed()
.collect(groupingBy(
i -> i / 3, //no longer i-1 because we start with 0
mapping(i -> list.get((int) i).toString(), joining(","))
));
//result: {0="1,2,3", 1="4,5,6", 2="7,8,9", 3="10"}
nous commençons par un IntStream
représentant les indices de la liste.
groupingBy
regroupe les éléments par un classificateur. Dans votre cas, il regroupe x éléments par page.
mapping
applique une fonction de mappage aux éléments et les recueille ensuite. Le la cartographie est nécessaire parce que joining
accepte uniquement CharSequence
. joining
rejoint lui-même les éléments en utilisant un délimiteur arbitraire.