scala 在Scala中映射数组时如何获取元素索引?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9137644/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 03:51:43  来源:igfitidea点击:

How to get the element index when mapping an array in Scala?

arraysscalamapscala-collections

提问by Ivan

Let's consider a simple mapping example:

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


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

What I need is to use not myFn(s: String): Stringhere, but myFn(s: String, n: Int): String, where nwould be the index of sin a. In this particular case myFn would expect the second argument to be 0 for s == "One", 1 for s == "Two" and 2 for s == "Three". How can I achieve this?

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

回答by Rex Kerr

Depends whether you want convenience or speed.

看你是要方便还是要速度。

Slow:

慢的:

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

Faster:

快点:

for (i <- a.indices) yield myFn(a(i),i)

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

Possibly fastest:

可能最快:

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

If not, this surely is:

如果没有,这肯定是:

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

(In Scala 2.10.1 with Java 1.6u37, if "possibly fastest" is declared to take 1x time for a trivial string operation (truncation of a long string to a few characters), then "slow" takes 2x longer, "faster" each take 1.3x longer, and "surely" takes only 0.5x the time.)

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

回答by missingfaktor

A general tip: Use .iteratormethod liberally, to avoid creation of intermediate collections, and thus speed up your computation. (Only when performance requirements demand it. Or else don't.)

一般提示:.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: 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)

Keep in mind that iterators are mutable, and hence once consumed cannot be used again.

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



An aside: The mapcall above involves de-tupling and then function application. This forces use of some local variables. You can avoid that using some higher order sorcery - convert a regular function to the one accepting tuple, and then pass it to map.

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

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

回答by Matthew Saltz

What about this? I think it should be fast and it's pretty. But I'm no expert on Scala speed...

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

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