web-dev-qa-db-ja.com

Scalaでmapを使用してインデックスを取得するにはどうすればよいですか?

mapのように動作し、要素のインデックスも提供するList/Sequenceビルトインはありますか?

94
Geo

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

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

次のようなバリエーションもあります。

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

または:

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

.zipWithIndexで.mapを使用

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

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

結果:

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

提案されたソリューションは、中間コレクションを作成したり、厳密に必要ではない変数を導入したりするという事実に苦しんでいます。最終的に行う必要があるのは、反復のステップ数を追跡することだけです。これは、メモ化を使用して実行できます。結果のコードは次のようになります

myIterable map (doIndexed(someFunction))

doIndexed- Functionは、インデックスとmyIterableの要素の両方を受け取る内部関数をラップします。これはJavaScriptでおなじみかもしれません。

この目的を達成する方法を次に示します。次のユーティリティを検討してください。

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

必要なのはこれだけです。これは、たとえば次のように適用できます。

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

リストになります

List(97, 99, 101)

このように、効果的な機能をラップすることを犠牲にして、通常のTraversable機能を使用できます。オーバーヘッドは、メモ化オブジェクトとその中のカウンターの作成です。それ以外の場合、このソリューションは、インデックス付けされていないmapを使用するのと同じくらいメモリ(またはパフォーマンス)の点で良い(または悪い)です。楽しい!

8
Matt Brasen

2.7.xにはCountedIteratorがあります(.countedを使用して通常のイテレーターから取得できます)。 2.8では非推奨(または単に削除)になったと思いますが、簡単にロールバックできます。イテレータに名前を付ける必要があります。

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

または、コレクションのアクセス時間が一定であると仮定すると、実際のコレクションの代わりにインデックスのリストをマップできます。

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

。map in 。zipWithIndexを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"
}

結果

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

マップ値も検索する必要がある場合(私がしたように):

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