Java 8: Trouver l'indice de la valeur minimale à partir d'une Liste
Dire que j'ai une liste avec des éléments (34, 11, 98, 56, 43)
.
À l'aide de Java 8 ruisseaux, comment puis-je trouver l'index de l'élément minimum de la liste (par exemple 1 dans ce cas)?
Je sais que cela peut être fait facilement en Java à l'aide de list.indexOf(Collections.min(list))
. Cependant, je suis en train de regarder un Scala comme solution où l'on peut tout simplement dire List(34, 11, 98, 56, 43).zipWithIndex.min._2
pour obtenir l'index de la valeur minimale.
Est-il quelque chose qui peut être fait en utilisant des ruisseaux ou des expressions lambda (disons Java 8 des caractéristiques spécifiques) pour obtenir le même résultat.
Note: C'est juste pour but d'apprentissage. Je n'ai pas de problème dans l'utilisation de Collections
les méthodes de l'utilitaire.
Vous devez vous connecter pour publier un commentaire.
Comme @TagirValeev mentionne dans sa réponse, vous pouvez éviter de boxe en utilisant
IntStream#reduce
au lieu deStream#min
, mais au prix d'occulter l'intention:zipWithIndex
cas, mais c'est peut-être l'idiome façon de résoudre ce problème. Je voudrais juste utiliserorElse(-1)
à la place.Vous pourriez le faire comme ceci:
Si la liste est aléatoire d'une liste d'accès,
get
est une constante de temps de l'opération. L'API manque d'une norme tuple de la classe, j'ai donc utilisé leSimpleEntry
de laAbstractMap
classe comme un substitut.Donc
IntStream.range
génère un flux d'index à partir de la liste à partir de laquelle vous avez la carte d'index de sa valeur correspondante. Vous obtenez alors le minimum de l'élément de fournir un élément de comparaison sur les valeurs (celles de la liste). De là, vous carte laOptional<SimpleEntry<Integer, Integer>>
à unOptional<Integer>
partir de laquelle vous obtenez l'indice (ou -1 si l'option est vide).En aparté, je serais probablement utiliser une simple boucle for pour obtenir l'index de la valeur minimum que votre combinaison de
min
/indexOf
n'2 passe au-dessus de la liste.Vous pourriez aussi être intéressé à vérifier La compression de flux à l'aide JDK8 avec lambda (java.util.stream.Streams.zip)
Collections
ou " Scala, à la mise en œuvre.Puisque c'est à des fins d'apprentissage, nous allons essayer de trouver une solution qui n'est pas juste en quelque sorte l'utilisation d'un flux, mais en fait, il fonctionne sur le courant de notre liste. Nous ne voulons pas assumer d'accès aléatoire.
Donc, il y a deux façons d'obtenir un non-trivial résultat d'un flux:
collect
etreduce
. Ici est une solution qui utilise un collectionneur:L'écriture d'un collectionneurs crée un ennuyeux quantité de code, mais il peut facilement être généralisé à l'appui de toute valeur comparable. Aussi, l'appel de la collector a l'air très idiomatiques:
Si l'on change le
accept
etcombine
méthodes de toujours renvoyer une nouvelleMinimum
instance (ie. si nous faisonsMinimum
immuable), nous pouvons également utiliserreduce
:Je sens un grand potentiel pour la parallélisation dans celui-ci.
Collector.of(Minimum::new, Minimum::accept, Minimum::combine, Minimum::getIndex)
au lieu de définir une classe anonyme.combine
méthode doit gérer correctement le cas deother
étant vide.Collector
javadoc exige en particulier que parallèlement à la convivialité de la "contrainte d'identité". Il ne dit rien sur le traitement de l'affaire dethis
étant vide etother
pas vide, mais il semble prudent de s'en charger.IntStreamEx.minBy
. Je commis une version fixe, sera probablement inclus dans ma lib.Voici deux solutions possibles à l'aide de mon StreamEx bibliothèque:
Ou:
La deuxième solution en interne est très proche de celui proposé par @AlexisC. Le premier est probablement le plus rapide car il n'utilise pas de boxe (en interne c'est une réduction de l'exploitation).
Sans l'aide de tiers code @Misha réponse semble la meilleure pour moi.