【问题标题】:How to get the element index when mapping an array in Scala?在Scala中映射数组时如何获取元素索引?
【发布时间】:2012-02-26 14:26:32
【问题描述】:

让我们考虑一个简单的映射示例:


  val a = Array("One", "Two", "Three")
  val b = a.map(s => myFn(s))

我需要在这里使用的不是myFn(s: String): String,而是myFn(s: String, n: Int): String,其中n 将是sa 中的索引。在这种特殊情况下,myFn 期望第二个参数对于 s == "One" 为 0,对于 s == "Two" 为 1,对于 s == "Three" 为 2。我怎样才能做到这一点?

【问题讨论】:

    标签: arrays scala map scala-collections


    【解决方案1】:

    取决于你想要方便还是速度。

    慢:

    a.zipWithIndex.map{ case (s,i) => myFn(s,i) }
    

    更快:

    for (i <- a.indices) yield myFn(a(i),i)
    
    { var i = -1; a.map{ s => i += 1; myFn(s,i) } }
    

    可能最快:

    Array.tabulate(a.length){ i => myFn(a(i),i) }
    

    如果不是,那肯定是:

    val b = new Array[Whatever](a.length)
    var i = 0
    while (i < a.length) {
      b(i) = myFn(a(i),i)
      i += 1
    }
    

    (在带有 Java 1.6u37 的 Scala 2.10.1 中,如果声明“可能最快”需要 1 倍时间进行简单的字符串操作(将长字符串截断为几个字符),则“慢”需要2 倍的时间,“更快”每个需要 1.3 倍的时间,而“肯定”只需要 0.5 倍的时间。)

    【讨论】:

    • 我喜欢阅读你关于速度问题的答案,但有时它会让人非常沮丧...... :-)
    • a.view.zipWithIndex.map{ case (s,i) =&gt; myFn(s,i) } 的速度与您的解决方案相比如何?
    • @gzm0 - 如果您确实需要所有值,甚至比最慢的速度还要慢(2-5 倍)。如果你只需要几个,那么视图会更好。
    【解决方案2】:

    一般提示:大量使用.iterator 方法,以避免创建中间集合,从而加快计算速度。 (仅当性能要求需要时。否则不需要。)

    scala> def myFun(s: String, i: Int) = s + i
    myFun: (s: String, i: Int)java.lang.String
    
    scala> Array("nami", "zoro", "usopp")
    res17: Array[java.lang.String] = Array(nami, zoro, usopp)
    
    scala> res17.iterator.zipWithIndex
    res19: java.lang.Object with Iterator[(java.lang.String, Int)]{def idx: Int; def idx_=(x$1: Int): Unit} = non-empty iterator
    
    scala> res19 map { case (k, v) => myFun(k, v) }
    res22: Iterator[java.lang.String] = non-empty iterator
    
    scala> res22.toArray
    res23: Array[java.lang.String] = Array(nami0, zoro1, usopp2)
    

    请记住,迭代器是可变的,因此一旦使用就不能再次使用。


    顺便说一句:上面的map 调用涉及去元组,然后是函数应用程序。这会强制使用一些局部变量。您可以使用一些高阶魔法来避免这种情况 - 将常规函数转换为接受元组的函数,然后将其传递给 map

    scala> Array("nami", "zoro", "usopp").zipWithIndex.map(Function.tupled(myFun))
    res24: Array[java.lang.String] = Array(nami0, zoro1, usopp2)
    

    【讨论】:

    • “迭代器是可变的,因此一旦使用就不能再次使用” - 我曾经花了一些时间调试为什么程序不能找到一个迭代器在使用后变空:-)
    【解决方案3】:

    这个呢?我认为它应该很快而且很漂亮。但我不是 Scala 速度方面的专家……

    a.foldLeft(0) ((i, x) => {myFn(x, i); i + 1;} )
    

    【讨论】:

      猜你喜欢
      • 2013-07-25
      • 1970-01-01
      • 2021-08-17
      • 2020-04-06
      • 1970-01-01
      • 2022-01-12
      • 2022-01-02
      • 2020-04-06
      • 1970-01-01
      相关资源
      最近更新 更多