【问题标题】:Get index of current element in a foreach method of Traversable?在Traversable的foreach方法中获取当前元素的索引?
【发布时间】:2011-10-12 20:48:17
【问题描述】:

假设我有两个数组:

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 的索引而不是首先构造整数列表,那就更好了。

也许有更好的方法?

【问题讨论】:

标签: scala


【解决方案1】:

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

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

【讨论】:

  • 通过添加变量修复了_的双重使用。
  • @RexKerr 你好,你能解释一下下划线是如何工作的吗?
  • @FrederickHONG - _1_2 是 Tuple2 的第一个和第二个元素(使用 zip 逐个元素创建)。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    这是在惯用的 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
    

    【讨论】:

      【解决方案4】:

      一个非常方便的方法是在元组上使用zipped 方法。放入两个集合,取出一个函数的两个参数!

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

      这既方便编写又快速,因为您不需要构建一个元组来存储每一对(就像您使用 (ar1 zip ar2) 所做的那样),然后您必须再次拆开它们。当两个系列中较短的一个用完时,两种形式的拉链都会停止。

      如果您有更复杂的事情(例如,您需要对索引进行数学运算),规范的解决方案是压缩索引:

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

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

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

      虽然这仅在第一个集合不长于第二个时才有效。您还可以明确指定您的范围:

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

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

      【讨论】:

      • 我没有回答这个问题,因为这个问题明确地询问了Traversable,而Traversable 没有zipWithIndex - 这是烦人
      • @WilfredSpringer - 这个问题询问Traversable,它只是建议想在某个时候使用foreach
      • 不要误会我的意思。我会投票赞成你的答案。我只是说问题是:“在 Traversable 的 foreach 方法中获取当前元素的索引?”所以看起来起点是有一个Traversable;至少这就是阅读问题的方式。
      • @WilfredSpringer - 好吧,很公平;这个问题确实提到了Traversable,即使问题本身表明你可以假设你有一个Seq。请注意,您必须处理 two 序列,这在单独使用 Traversable 时本质上是不可能的,除非您在单独的线程和块中运行每个序列 - 对于一个简单的问题来说,这是一个非常缓慢和复杂的解决方案 - - 或 O(n^2) 性能,这对于固有的 O(n) 问题来说是可怕的。 (真正的问题是foreach不是一个很灵活的操作。)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-20
      • 2021-05-23
      • 1970-01-01
      • 2016-08-21
      • 1970-01-01
      相关资源
      最近更新 更多