2010-02-06 8 views

Odpowiedz

122

wierzę szukasz 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 

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

mieć również odmiany, takie jak:

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

lub:

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

Czy to skuteczne? – ziggystar

+50

Nie. Wolałbym zrobić: println ("0 Mary \ n1 miał \ n2 a \ n3 mały \ n4 jagnię") –

+2

Cóż, miałem na myśli użycie metody 'zipWithIndex', aby uzyskać indeks wewnątrz pętli/mapy/cokolwiek . – ziggystar

5

Istnieje CountedIterator w pliku 2.7.x (który można uzyskać z normalnego iteratora z. Counted). Wydaje mi się, że został wycofany (lub po prostu usunięty) w wersji 2.8, ale łatwo jest przetasować własny. Trzeba, aby móc nazwać iterator:

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) 
3

Albo, zakładając swoją kolekcję ma czas stały dostęp, można odwzorować lista indeksów zamiast rzeczywistej kolekcji:

val ls = List("a","b","c") 
0.until(ls.length).map(i => doStuffWithElem(i,ls(i))) 
+1

Bardziej eleganckim sposobem na to jest: 'ls.indices.map (i => doStuffWithElem (i, ls (i))' –

+3

@aksiksi No cóż, widząc, że [indeksy] są zaimplementowane jako '0 aż do length'] (https://github.com/scala/scala/blob/2.12.x/src/library/scala/collection/SeqLike.scala#L668) To prawie to samo: P –

+0

hahaha wygrywasz: D –

8

Proponowane rozwiązania polegają na tym, że tworzą kolekcje pośrednie lub wprowadzają zmienne, które nie są bezwzględnie konieczne. Ostatecznie wszystko, co musisz zrobić, to śledzić liczbę kroków w iteracji. Można to zrobić za pomocą notowania. Otrzymany kod może wyglądać

myIterable map (doIndexed(someFunction)) 

doIndexed -Function owija funkcję wewnętrznego, który odbiera zarówno indeksowany z elementów myIterable. To może być ci znane z JavaScript.

Oto sposób osiągnięcia tego celu. Rozważ następujące narzędzie:

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) 
    } 
} 

To wszystko, czego potrzebujesz. Można zastosować to na przykład w następujący sposób:

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

co powoduje listy

List(97, 99, 101) 

W ten sposób można używać zwykłych przesuwny-funkcje kosztem owijając swoją skuteczną funkcję. Narzut jest tworzeniem obiektu do zapamiętania i licznika w nim. W przeciwnym razie to rozwiązanie jest tak samo dobre (lub złe) pod względem pamięci lub wydajności, jak przy użyciu indeksu niepotwierdzonego map. Cieszyć się!

+1

To jest bardzo eleganckie rozwiązanie problemu +1 dla nie tworzenia tymczasowej kolekcji. t działa w kolekcja równoległa, ale wciąż bardzo ładne rozwiązanie. – fbl

+3

Jeśli nie chcesz tworzyć kolekcji tymczasowej, po prostu użyj 'coll.view.zipWithIndex' zamiast' coll.zipWithIndex' – tsuna

33

Użyj. mapa w. zipWithIndex

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

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

Wynik:

List("a(0)", "b(1)", "c(2)") 
+4

Jest to pierwszy przyzwoity przykład, jaki widziałem, który użył 'mapy' zgodnie z żądaniem zamiast właśnie drukowanie wewnątrz "foreach". –