web-dev-qa-db-fra.com

Comment puis-je utiliser map et recevoir un index également en Scala?

Existe-t-il une liste/séquence intégrée qui se comporte comme map et fournit également l'index de l'élément?

89
Geo

Je crois que vous cherchez zipWithIndex?

scala> val ls = List("Mary", "had", "a", "little", "lamb")
scala> ls.zipWithIndex.foreach{ case (e, i) => println(i+" "+e) }
0 Mary
1 had
2 a
3 little
4 lamb

De: http://www.artima.com/forums/flat.jsp?forum=283&thread=243570

Vous avez aussi des variations comme: 

for((e,i) <- List("Mary", "had", "a", "little", "lamb").zipWithIndex) println(i+" "+e)

ou:

List("Mary", "had", "a", "little", "lamb").zipWithIndex.foreach( (t) => println(t._2+" "+t._1) )
131
Viktor Klang

Utilisez . map in . zipWithIndex

val myList = List("a", "b", "c")

myList.zipWithIndex.map { case (element, index) => 
   println(element, index) 
   s"${element}(${index})"
}

Résultat:

List("a(0)", "b(1)", "c(2)")
45
Paulo Cheque

Les solutions proposées souffrent du fait qu'elles créent des collections intermédiaires ou introduisent des variables qui ne sont pas strictement nécessaires. En fin de compte, tout ce que vous avez à faire est de suivre le nombre d’étapes d’une itération. Cela peut être fait en utilisant memoizing. Le code résultant pourrait ressembler à

myIterable map (doIndexed(someFunction))

La fonction doIndexed- englobe la fonction intérieure qui reçoit un index et les éléments de myIterable. Cela vous est peut-être familier à partir de JavaScript.

Voici un moyen d'atteindre cet objectif. Considérez l'utilitaire suivant:

object TraversableUtil {
    class IndexMemoizingFunction[A, B](f: (Int, A) => B) extends Function1[A, B] {
        private var index = 0
        override def apply(a: A): B = {
            val ret = f(index, a)
            index += 1
            ret
        }
    }

    def doIndexed[A, B](f: (Int, A) => B): A => B = {
        new IndexMemoizingFunction(f)
    }
}

C'est déjà tout ce dont vous avez besoin. Vous pouvez appliquer cela par exemple comme suit:

import TraversableUtil._
List('a','b','c').map(doIndexed((i, char) => char + i))

qui résulte dans la liste

List(97, 99, 101)

De cette façon, vous pouvez utiliser les fonctions habituelles de Traversable au détriment de l'encapsulation de votre fonction efficace. Le temps système est la création de l'objet mémoizing et du compteur qui s'y trouve. Sinon, cette solution est aussi bonne (ou mauvaise) en termes de mémoire ou de performances que d'utiliser map non indexée. Prendre plaisir!

8
Matt Brasen

Il y a CountedIterator dans 2.7.x (que vous pouvez obtenir à partir d'un itérateur normal avec .counted). Je crois que cela a été déconseillé (ou simplement supprimé) en 2.8, mais il est assez facile de lancer le vôtre. Vous devez être capable de nommer l'itérateur:

val ci = List("These","are","words").elements.counted
scala> ci map (i => i+"=#"+ci.count) toList
res0: List[Java.lang.String] = List(These=#0,are=#1,words=#2)
5
Rex Kerr

Ou, en supposant que votre collection ait un temps d'accès constant, vous pouvez mapper la liste des index au lieu de la collection réelle:

val ls = List("a","b","c")
0.until(ls.length).map( i => doStuffWithElem(i,ls(i)) )
3
Cristian Vrabie

Utilisez .map in .zipWithIndex avec la structure de données Map

val sampleMap = Map("a" -> "hello", "b" -> "world", "c" -> "again")

val result = sampleMap.zipWithIndex.map { case ((key, value), index) => 
    s"Key: $key - Value: $value with Index: $index"
}

Résultats

 List(
       Key: a - Value: hello with Index: 0, 
       Key: b - Value: world with Index: 1, 
       Key: c - Value: again with Index: 2
     )
0
fgfernandez0321

Si vous souhaitez également rechercher les valeurs de la carte (comme je le devais):

val ls = List("a","b","c")
val ls_index_map = ls.zipWithIndex.toMap 
0
Yair Beer