如何在 Scala 中使用 map 和接收索引?

是否有任何类似于 map并提供元素索引的 List/Sequence 内置?

77384 次浏览

在2.7. x 中有 CountedIterator(您可以通过使用。计算)。我相信它在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)

I believe you're looking for 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=243570

你也可以有这样的变化:

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

或者,假设您的集合具有固定的访问时间,您可以映射索引列表,而不是实际的集合:

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

所提出的解决方案受到这样一个事实的影响,即它们创建了中间集合或引入了并非绝对必要的变量。因为最终您需要做的就是跟踪迭代的步骤数。这可以通过使用制表来完成。结果代码可能看起来像

myIterable map (doIndexed(someFunction))

函数包装了内部函数,它同时接收一个索引和 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)

This way, you can use the usual Traversable-functions at the expense of wrapping your effective function. The overhead is the creation of the memoizing object and the counter therein. Otherwise this solution is as good (or bad) in terms of memory or performance as using unindexed map. Enjoy!

使用。 地图在。 ZipWithIndex

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

如果您也需要搜索 map 值(像我一样) :

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

Use 。地图 in .zipWithIndex with Map data structure

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
)

有两种方法可以做到这一点。

ZipWithIndex: 创建一个自动从0开始的计数器。

  // zipWithIndex with a map.
val days = List("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat")
days.zipWithIndex.map {
case (day, count) => println(s"$count is $day")
}
// Or use it simply with a for.
for ((day, count) <- days.zipWithIndex) {
println(s"$count is $day")
}

这两个代码的输出将是:

0 is Sun
1 is Mon
2 is Tue
3 is Wed
4 is Thu
5 is Fri
6 is Sat

Zip: Use zip method with a Stream to create a counter. This gives you a way to control the starting value.

for ((day, count) <- days.zip(Stream from 1)) {
println(s"$count is $day")
}

Result:

1 is Sun
2 is Mon
3 is Tue
4 is Wed
5 is Thu
6 is Fri
7 is Sat