リストからインデクスをキーとしたマップを生成

まれに必要になる処理なのですが、美しく書くにはどうしたものか・・・
リストのサイズと Range を使えばもっとシンプルにかけることに気付きました。というか、気付けよ私(ase


scala> val list = List("foo", "bar", "baz")
list: List[java.lang.String] = List(foo, bar, baz)

scala> val map = Map((0 to list.size).toList.zip(list): _*)
map: scala.collection.immutable.Map[Int,java.lang.String] = Map(0 -> foo, 1 -> bar, 2 -> baz)

scala>

(0 to list.size) で、0, 1, 2, 3 の Range を作っています。3 が余分ですが zip で捨てられるので気にしない方向で。
今のところ foldLeft と zip と Map.apply をつかって書いてます。

scala> val list = List("foo", "bar", "baz")
list: List[java.lang.String] = List(foo, bar, baz)

scala> val indexes = (List[Int]() /: list) { (x, y) => x match {
| case head::_ => (head+1)::x
| case _ => List(0)
| } } reverse
indexes: List[Int] = List(0, 1, 2)

scala> val map = Map(indexes.zip(list): _*)
map: scala.collection.immutable.Map[Int,java.lang.String] = Map(0 -> foo, 1 -> bar, 2 -> baz)

scala>

インデクスをキーにするのではなく、リスト要素の属性なりをキーにするのであれば、indexes を作っている部分はもっと簡単に map だけですみますね。

以下、hashCode をキーにした場合のコード例です。


scala> val map = Map(list.map(_.hashCode).zip(list): _*)
map: scala.collection.immutable.Map[Int,java.lang.String] = Map(101574 -> foo, 97299 -> bar, 97307 -> baz)

ポイントとしては、Map.apply の引数は可変長なので、_* をつけて展開して渡しています。
通常の使用であれば Map( (0 -> "foo"), (1 -> "bar"), (2 -> "baz") ) のように、任意の個数を引数として渡すのですが、List(というか Seq) の中身を渡したい場合は _* をつける必要があります。