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

Geo*_*Geo 96 functional-programming scala map

是否存在任何类似的List/Sequence map并提供元素的索引?

Vik*_*ang 141

我相信你在寻找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
Run Code Online (Sandbox Code Playgroud)

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

您还有以下变体:

for((e,i) <- List("Mary", "had", "a", "little", "lamb").zipWithIndex) println(i+" "+e)
Run Code Online (Sandbox Code Playgroud)

要么:

List("Mary", "had", "a", "little", "lamb").zipWithIndex.foreach( (t) => println(t._2+" "+t._1) )
Run Code Online (Sandbox Code Playgroud)

  • 好吧,我的意思是使用`zipWithIndex`方法来获取循环/ map /中的索引. (3认同)
  • @ziggystar如果你正在寻找性能,你需要权衡一些不变性.查看zipWithIndex函数.它只是使用var来构建一个新的对集合.您可以使用相同的方法来增加var而不构建新集合,就像在Java中一样.但它不是功能风格.想想你是否真的需要它. (2认同)

Pau*_*que 50

使用 .地图.zipWithIndex

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

myList.zipWithIndex.map { case (element, index) => 
   println(element, index) 
   s"${element}(${index})"
}
Run Code Online (Sandbox Code Playgroud)

结果:

List("a(0)", "b(1)", "c(2)")
Run Code Online (Sandbox Code Playgroud)

  • 这是我见过的第一个体面的例子,它使用了`map`作为请求,而不是仅仅在`foreach`中打印. (9认同)

小智 8

所提出的解决方案遭受以下事实:它们创建中间集合或引入非严格必要的变量.最终,您需要做的就是跟踪迭代的步骤数.这可以使用memoizing完成.生成的代码可能看起来像

myIterable map (doIndexed(someFunction))
Run Code Online (Sandbox Code Playgroud)

doIndexed-功能包,其接收两个的索引的的元素的内部功能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)
    }
}
Run Code Online (Sandbox Code Playgroud)

这已经是你所需要的了.您可以应用此实例,如下所示:

import TraversableUtil._
List('a','b','c').map(doIndexed((i, char) => char + i))
Run Code Online (Sandbox Code Playgroud)

这导致了清单

List(97, 99, 101)
Run Code Online (Sandbox Code Playgroud)

这样,您可以使用通常的Traversable函数,但代价是包装有效函数.开销是在其中创建记忆对象和计数器.否则,此解决方案在内存或性能方面与使用未编制索引一样好(或差)map.请享用!

  • 如果你不想创建一个临时集合,只需使用`coll.view.zipWithIndex`而不是`coll.zipWithIndex` (4认同)

Rex*_*err 5

CountedIterator在2.7.x(你可以从.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)
Run Code Online (Sandbox Code Playgroud)


Cri*_*bie 5

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

val ls = List("a","b","c")
0.until(ls.length).map( i => doStuffWithElem(i,ls(i)) )
Run Code Online (Sandbox Code Playgroud)

  • @aksiksi 好吧,看到 [`indices` 实现为 `0 until length`](https://github.com/scala/scala/blob/2.12.x/​​src/library/scala/collection/SeqLike.scala# L668)几乎是一样的:P (3认同)
  • 一个更优雅的方法是:`ls.indices.map(i =&gt; doStuffWithElem(i, ls(i))` (2认同)
  • @MosheBixenshpaner 足够公平。我的“List”示例确实很差。但是,我确实提到过,如果您的收藏具有恒定的访问时间,这很合适。应该选择`Array`。 (2认同)

Mad*_*ffs 5

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

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")
  }
Run Code Online (Sandbox Code Playgroud)

两个代码的输出均为:

0 is Sun
1 is Mon
2 is Tue
3 is Wed
4 is Thu
5 is Fri
6 is Sat
Run Code Online (Sandbox Code Playgroud)

Zip:使用 zip 方法和 Stream 来创建计数器。这为您提供了一种控制起始值的方法。

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

结果:

1 is Sun
2 is Mon
3 is Tue
4 is Wed
5 is Thu
6 is Fri
7 is Sat
Run Code Online (Sandbox Code Playgroud)