编写2D数组的迭代器

时间:2011-03-18 14:09:30

标签: arrays scala iterator

我正在尝试为2D数组编写迭代器。以下是我的想法。

  def rowsTest() {
    val array = Array(
      Array(9, 11, 4, 89),
      Array(7, 62, 34, 2),
      Array(3, 4, 5, 12),
      Array(13, 4, 5, 12),
      Array(3, 24, 5, 12),
      Array(3, 4, 35, 12)
    )
    def rows: Iterator[Iterator[Int]] = {
      new Iterator[Iterator[Int]] {
        private var rowIndex = 0

        def hasNext: Boolean = rowIndex < 6

        def next: Iterator[Int] = {
          val rowIterator = new Iterator[Int] {
            private var columnIndex = 0

            def next: Int = {
              val p = array(columnIndex)(rowIndex)
              columnIndex += 1
              println("ColIndex = "+ columnIndex.toString)
              p
            }

            def hasNext: Boolean = columnIndex < 4
          }
          rowIndex += 1
          println("RowIndex = "+ rowIndex.toString)
          rowIterator
        }
      }
    }
    for(row <- rows; elem <- row)
      println(elem)
  }

运行时上面的代码会跳过第一行,并且在打印完所有元素时也会给出ArrayIndexOutOfBoundsException。你能帮我弄明白我哪里出错吗?

谢谢你,
Siddharth Raina。

3 个答案:

答案 0 :(得分:5)

以下代码怎么样?

val array = Array(Array(1,2,3),Array(4,5,6),Array(7,8,9))
array.view.flatten.iterator

在REPL中测试它是有效的。虽然我不知道我是否通过“观点”实现了我的意图。欢迎提出任何意见。

修改

我忘记了作者想要一个嵌套的迭代器。

array.iterator.map(_.iterator)

这当然没有“视图”而且没有开销。

答案 1 :(得分:3)

我无法从你的代码中知道你真正想做什么。

如果你想用迭代器的迭代器遍历你的数组,那么已经有了一个简单的方法:

val a2d = Array.tabulate(4,4)((i,j)=>4*i+j)
a2d.iterator.map(_.iterator)

如果你决定要一个迭代器,你也可以这样做:

a2d.iterator.flatMap(_.iterator)

如果你想遍历 columns ,即使数组按行主顺序排序,那么你还有一些工作要做(我认为这是你想要做的,但是你混淆了你的数组索引,也许还有其他一些东西):

def iterateColumns(aai: Array[Array[Int]]) = new Iterator[Iterator[Int]] {
  private[this] var j = -1
  private[this] val shortest = if (aai.length==0) 0 else aai.map(_.length).min
  def hasNext = j+1 < shortest
  def next = {
    j += 1
    new Iterator[Int] {
      private[this] var i = -1
      def hasNext = i+1 < aai.length
      def next = {
        i += 1
        aai(i)(j)
      }
    }
  }
}

现在你可以

scala> for (row <- a2d.iterator.map(_.iterator)) println(row.mkString(" "))
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15

scala> for (col <- iterateColumns(a2d)) println(col.mkString(" "))
0 4 8 12
1 5 9 13
2 6 10 14
3 7 11 15

(你也应该能够a2d.view.transpose.iterator.map(_.iterator)来避免制作副本,但不幸的是,这看起来并不像你希望的那样2.8.1。

答案 2 :(得分:1)

如果你想以命令式的方式手工制作:

  def rowsTest() {
    val array = Array(
      Array(9, 11, 4, 89),
      Array(7, 62, 34, 2),
      Array(3, 4, 5, 12),
      Array(13, 4, 5, 12),
      Array(3, 24, 5, 12),
      Array(3, 4, 35, 12)
    )
    def rows: Iterator[Iterator[Int]] = {
      new Iterator[Iterator[Int]] {
        private var rowIndex = 0
        def hasNext: Boolean = rowIndex < 6
        def next: Iterator[Int] = {
          // fix row index for inner iterator
          val rowIdx = rowIndex
          val rowIterator = new Iterator[Int] {
            private var columnIndex = 0
            def next: Int = {
              // swap indices!!!
              val p = array(rowIdx)(columnIndex)
              columnIndex += 1
              println("ColIndex = " + columnIndex.toString)
              p
            }
            def hasNext: Boolean = columnIndex < 4
          }
          rowIndex += 1
          println("RowIndex = " + rowIndex.toString)
          rowIterator
        }
      }
    }
    for (row <- rows; elem <- row)
      println(elem)
  }

但是

val rows: Iterator[Iterator[Int]] = array.iterator.map(_.iterator)
ziggystar的

仍然更好,因为它也适用于非矩形2D阵列,并且更加简洁和“scalaish”。