Liste Java 8 à mapper avec le stream

J’ai une collection List . Je dois le convertir en Map La clé de la carte doit être l’index de l’élément dans la collection. Je ne peux pas comprendre comment faire cela avec des stream. Quelque chose comme:

 items.stream().collect(Collectors.toMap(...)); 

De l’aide?

Comme cette question est identifiée comme possible en double, je dois append que mon problème concret était: comment obtenir la position de l’élément dans la liste et la mettre comme valeur clé

Vous pouvez créer un Stream des index à l’aide d’un IntStream , puis les convertir en Map :

 Map map = IntStream.range(0,items.size()) .boxed() .collect(Collectors.toMap (i -> i, i -> items.get(i))); 

Une autre solution pour la complétude consiste à utiliser le collecteur personnalisé:

 public static  Collector> toMap() { return Collector.of(HashMap::new, (map, t) -> map.put(map.size(), t), (m1, m2) -> { int s = m1.size(); m2.forEach((k, v) -> m1.put(k+s, v)); return m1; }); } 

Usage:

 Map map = items.stream().collect(toMap()); 

Cette solution est compatible avec les applications parallèles et ne dépend pas de la source (vous pouvez utiliser la liste sans access aléatoire ou Files.lines() ou autre).

Ne vous sentez pas obligé de tout faire dans / avec le stream. Je voudrais juste faire:

 AtomicInteger index = new AtomicInteger(); items.stream().collect(Collectors.toMap(i -> index.getAndIncrement(), i -> i)); 

Tant que vous ne paralléliserez pas le stream, cela fonctionnera et évite les opérations get() et indexOf() potentiellement coûteuses et / ou problématiques (en cas de doublons).

(Vous ne pouvez pas utiliser une variable int régulière à la place d’ AtomicInteger car les variables utilisées en dehors d’une expression lambda doivent être effectivement finales. Notez que lorsque vous n’êtes pas contesté (comme dans ce cas), AtomicInteger est très rapide et ne pose aucun problème de performances. Mais si cela vous inquiète, vous pouvez utiliser un compteur non-thread-safe.)

Ceci est une réponse mise à jour et ne présente aucun des problèmes mentionnés dans les commentaires.

 Map outputMap = IntStream.range(0,inputList.size()).boxed().collect(Collectors.toMap(Function.identity(), i->inputList.get(i))); 

En utilisant une bibliothèque tierce ( protonpack par exemple, mais il y en a d’autres), vous pouvez zip la valeur avec son index et le tour est joué:

 StreamUtils.zipWithIndex(items.stream()) .collect(Collectors.toMap(Indexed::getIndex, Indexed::getValue)); 

Bien que getIndex renvoie un long , vous devrez peut-être le lancer en utilisant quelque chose de similaire à:

 i -> Integer.valueOf((int) i.getIndex()) 

La réponse d’Eran est généralement la meilleure approche pour les listes à access aléatoire.

Si votre List n’est pas un access aléatoire ou si vous avez un Stream plutôt qu’une List , vous pouvez utiliser forEachOrdered :

 Stream stream = ... ; Map map = new HashMap<>(); AtomicInteger index = new AtomicInteger(); stream.forEachOrdered(item -> map.put(index.getAndIncrement(), item)); 

Ceci est sûr si le stream est parallèle, même si la carte de destination est dangereuse pour les threads et est utilisée comme effet secondaire. forEachOrdered garantit que les éléments sont traités un par un, dans l’ordre. Pour cette raison, il est peu probable que des accélérations se produisent en parallèle. (Il pourrait y avoir une accélération s’il y a des opérations coûteuses dans le pipeline avant le forEachOrdered .)