在Traversable的foreach方法中获取当前元素的索引?

时间:2011-07-25 19:23:26

标签: scala

假设我有两个数组:

val ar1 = Array[String]("1", "2", "3")
val ar2 = Array[String]("1", "2", "3", "4")

现在对于ar1的每个元素,我想首先将该元素与ar2的相应元素连接起来,然后打印结果。一种方法是:

List.range(0, ar1.size).foreach(i => println(ar1(i)+ar2(i)))

如果有foreach变体允许我直接使用ar1的索引而不是首先构造整数列表,那会更好。

也许有更好的方法?

4 个答案:

答案 0 :(得分:91)

执行此操作的一种非常方便的方法是使用元组上的zipped方法。放入两个集合,得到一个函数的两个参数!

(ar1,ar2).zipped.foreach((x,y) => println(x+y))

这既便于编写又快速,因为您不需要构建一个元组来存储每对(就像使用(ar1 zip ar2)那样),然后您必须再次拆分。当两个集合中较短的一个用尽时,两种形式的zip都会停止。

如果你有更复杂的东西(例如你需要对索引进行数学运算),那么规范的解决方案就是在索引中输入:

ar1.zipWithIndex.foreach{ case(x,i) => println(x+ar2(i)) }

您正在使用的方法更快速,更紧凑,如下所示,这可能很有用:

ar1.indices.foreach(i => println(ar1(i)+ar2(i)))

虽然只有在第一个集合不长于第二个集合时才有效。您还可以explcitly指定范围:

(0 until (ar1.size min ar2.size)).foreach(i => println(ar1(i)+ar2(i)))

解决这个问题。 (您可以看到为什么zipzipped是首选,除非您正在做的事情太复杂,以至于无法轻松工作。)

如果它不是并行集合(通常除非你调用.par,它通常不会),尽管不推荐,也可以跟踪一个可变变量:

{ var i=-1; ar1.foreach{ x => i += 1; println(x+ar2(i)) } }

有必要的情况非常有限(例如,如果您可能想跳过或回溯某些其他集合);如果你可以避免这样做,你通常会得到更容易推理的代码。

答案 1 :(得分:38)

这是你在惯用Scala中循环索引的方法:

scala> List("A", "B", "C").zipWithIndex foreach { case(el, i) =>
     |   println(i + ": " + el)
     | }
0: A
1: B
2: C

以下是您在代码中尝试实现的惯用Scala方法:

scala> val arr1 = Array("1", "2", "3")
arr1: Array[java.lang.String] = Array(1, 2, 3)

scala> val arr2 = Array("1", "2", "3", "4")
arr2: Array[java.lang.String] = Array(1, 2, 3, 4)

scala> (arr1, arr2).zipped.map(_ + _) foreach println
11
22
33

答案 2 :(得分:4)

我没有机会测试它,但这应该可以解决问题:

ar1.zip(ar2).foreach(x => println(x._1 +x._2))

答案 3 :(得分:3)

zip会这样做:

ar1 zip ar2 foreach { p => println(p._1 + p._2) }

这将产生:

11
22
33

请注意,编译器不需要[String]泛型类型:

val ar1 = Array("1", "2", "3")
val ar2 = Array("1", "2", "3", "4")