开发者

Writing an iterator for a 2D array

I am trying to write an iterator for a 2D array. The 开发者_开发知识库following is what I have come up with.

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

The above code when run skips the first row, and also gives an ArrayIndexOutOfBoundsException when all elements have been printed. Can you help me figure out where I've gone wrong?

Thank you,

Siddharth Raina.


How about the following code?

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

It works, as tested in REPL. Though I don't know if I achieve what I intended with "view". Any comments are welcome.

Edit

I forgot the author wanted a nested iterator.

array.iterator.map(_.iterator)

This certainly works without the "view" and without overhead.


I can't tell from your code what you actually want to do.

If you want traverse your array with iterators of iterators, there's already an easy way to do it:

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

And if you decide you want a single iterator, you can do that too:

a2d.iterator.flatMap(_.iterator)

If you want to traverse columns even though the array is in row-major order, then you have a little more work to do (which I think is what you were trying to do, but you mixed up your array indices, and maybe some other things):

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

Now you can

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

(You also ought to be able to do a2d.view.transpose.iterator.map(_.iterator) to avoid making a copy, but unfortunately it doesn't look like this works the way you'd hope in 2.8.1.)


If you want to do it handmade in an imperative style:

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

but the

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

of ziggystar is still better because its work with non rectangular 2D-arrays too and is more consice and "scalaish".

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜