Comment puis-je utiliser map et recevoir un index aussi bien dans 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?

88
demandé sur Geo 2010-02-06 16:59:47

5 réponses

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

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

Vous avez aussi des variantes 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) )
130
répondu Viktor Klang 2010-02-07 22:35:45

Utilisation . Carte dans .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)")
42
répondu Paulo Cheque 2014-09-04 21:09:52

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. Pour en fin de compte tout ce que vous devez faire est de garder une trace du nombre d'étapes d'une itération. Cela peut être fait en utilisant la mémorisation. Le code résultant pourrait ressembler à

myIterable map (doIndexed(someFunction))

La Fonction doIndexed enveloppe la fonction intérieure qui reçoit à la fois un index et les éléments de myIterable. Cela pourrait vous être familier à partir de JavaScript.

Voici un façon d'atteindre ce but. 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 l'appliquer par exemple comme suit:

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

Qui aboutit à la liste

List(97, 99, 101)

De cette façon, vous pouvez utiliser les fonctions traversables habituelles au détriment de l'emballage de votre fonction effective. La surcharge est la création de l'objet de mémorisation et du compteur qui s'y trouve. Sinon, cette solution est aussi bonne (ou mauvaise) en termes de mémoire ou de performance que d'utiliser unindexed map. Amusez-vous bien!

8
répondu Matt Brasen 2012-05-09 09:41:42

Il y a {[1] } dans 2.7.x (que vous pouvez obtenir à partir d'un itérateur .compter). Je crois qu'il a été déprécié (ou simplement supprimé) en 2.8, mais il est assez facile de rouler 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
répondu Rex Kerr 2010-02-06 14:48:19

Ou, en supposant que votre collection a 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
répondu Cristian Vrabie 2012-03-12 11:03:10