ScalaでのJavaコレクションの反復


113

Apache POI API を使用するいくつかのScalaコードを書いています。java.util.IteratorSheetクラスから取得したに含まれる行を反復処理したいと思います。イテレータをfor eachスタイルループで使用したいので、ネイティブのScalaコレクションに変換しようとしていますが、うまくいきません。

Scalaのラッパークラス/特性を確認しましたが、それらを正しく使用する方法がわかりません。while(hasNext()) getNext()ループの詳細スタイルを使用せずにScalaでJavaコレクションを反復するにはどうすればよいですか?

正しい答えに基づいて私が書いたコードは次のとおりです。

class IteratorWrapper[A](iter:java.util.Iterator[A])
{
    def foreach(f: A => Unit): Unit = {
        while(iter.hasNext){
          f(iter.next)
        }
    }
}

object SpreadsheetParser extends Application
{
    implicit def iteratorToWrapper[T](iter:java.util.Iterator[T]):IteratorWrapper[T] = new IteratorWrapper[T](iter)

    override def main(args:Array[String]):Unit =
    {
        val ios = new FileInputStream("assets/data.xls")
        val workbook = new HSSFWorkbook(ios)
        var sheet = workbook.getSheetAt(0)
        var rows = sheet.rowIterator()

        for (val row <- rows){
            println(row)
        }
    }
}

パーサーが '<'文字がXML終了タグであると考えずに "for(val row <-rows){"という行を含めることができないようです。バック
ティックが機能

暗黙的にIteratirWrapperに変換できるため、かなりの構文を節約できます。Scalaでの暗黙的な変換のためのGoogle。
Daniel Spiewak、2009年

回答:


28

ラッパークラス(scala.collection.jcl.MutableIterator.Wrapper)があります。したがって、定義すると

implicit def javaIteratorToScalaIterator[A](it : java.util.Iterator[A]) = new Wrapper(it)

その後、Scalaイテレータのサブクラスとして機能するため、実行できますforeach


読みます:scala.collection.jcl.MutableIterator.Wrapper
samg

37
この回答はScala 2.8では廃止されました。stackoverflow.com/questions/2708990/…を
Alex R

256

Scala 2.8からは、適切な変換がすでに宣言されているJavaConversionsオブジェクトをインポートするだけで済みます。

import scala.collection.JavaConversions._

ただし、これは以前のバージョンでは機能しません。


24

編集:Scala 2.13.0は廃止予定なscala.collection.JavaConvertersので、2.13.0以降は使用する必要がありますscala.jdk.CollectionConverters

Scala 2.12.0は非推奨scala.collection.JavaConversionsであるため、2.12.0以降、これを行う1つの方法は次のようになります。

import scala.collection.JavaConverters._

// ...

for(k <- javaCollection.asScala) {
    // ...
}

(インポートに注意してください、新しいものはJavaConverters、非推奨はJavaConversionsです)


2
「toScala」を探していました^ _ ^!
プロフィットロール

15

ここでの正解は、JavaからIteratorカスタムタイプへの暗黙的な変換を定義することです。この型はforeach、基になるに委譲するメソッドを実装する必要がありますIterator。これによりfor、任意のJavaでScala ループを使用できるようになりますIterator


9

Scala 2.10の場合:

// Feature warning if you don't enable implicit conversions...
import scala.language.implicitConversions
import scala.collection.convert.WrapAsScala.enumerationAsScalaIterator

5

Scala 2.10.4+(およびおそらく以前のバージョン)では、scala.collection.JavaConversions.asScalaIteratorをインポートすることにより、java.util.Iterator [A]をscala.collection.Iterator [A]に暗黙的に変換することが可能です。次に例を示します。

object SpreadSheetParser2 extends App {

  import org.apache.poi.hssf.usermodel.HSSFWorkbook
  import java.io.FileInputStream
  import scala.collection.JavaConversions.asScalaIterator

  val ios = new FileInputStream("data.xls")
  val workbook = new HSSFWorkbook(ios)
  var sheet = workbook.getSheetAt(0)
  val rows = sheet.rowIterator()

  for (row <- rows) {
    val cells = row.cellIterator()
    for (cell <- cells) {
      print(cell + ",")
    }
    println
  }

}

4

Javaコレクションを配列に変換し、それを使用することができます。

val array = java.util.Arrays.asList("one","two","three").toArray
array.foreach(println)

または続けて、配列をScalaリストに変換します。

val list = List.fromArray(array)

4

大規模なデータセットを反復処理する場合は、.asScala暗黙的な変換を使用してコレクション全体をメモリにロードしたくない場合があります。この場合、便利な方法は、scala.collection.Iterator特性を実装することです

import java.util.{Iterator => JIterator}

def scalaIterator[T](it: JIterator[T]) = new Iterator[T] {
  override def hasNext = it.hasNext
  override def next() = it.next()
} 

val jIterator: Iterator[String] = ... // iterating over a large dataset
scalaIterator(jIterator).take(2).map(_.length).foreach(println)  // only first 2 elements are loaded to memory

コンセプトは似ていますが、IMOは冗長ではありません:)


2

あなたはで暗黙を避けたい場合scala.collection.JavaConversions使用できるscala.collection.JavaConvertersを明示的に変換すること。

scala> val l = new java.util.LinkedList[Int]()
l: java.util.LinkedList[Int] = []

scala> (1 to 10).foreach(l.add(_))

scala> val i = l.iterator
i: java.util.Iterator[Int] = java.util.LinkedList$ListItr@11eadcba

scala> import scala.collection.JavaConverters._
import scala.collection.JavaConverters._

scala> i.asScala.mkString
res10: String = 12345678910

asScalaメソッドを使用してJava IteratorをScala に変換することに注意してくださいIterator

JavaConvertersはScala 2.8.1以降で利用可能です。


私 はあなたの例から使用しimport scala.collection.JavaConverters._ 、それ javaList.iterator().asScalaは機能しました
kosiara-Bartosz Kosarzycki
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.