Apache POI APIを使用するScalaコードを書いています。 Sheetクラスから取得した_Java.util.Iterator
_に含まれる行を繰り返したいと思います。イテレータを_for each
_スタイルのループで使用したいので、ネイティブのScalaコレクションに変換しようとしましたが、うまくいきません。
Scalaラッパークラス/特性を見てきましたが、それらを正しく使用する方法がわかりません。冗長while(hasNext()) getNext()
スタイルのループを使用せずにJavaのScalaコレクションを反復処理するにはどうすればよいですか?
正解に基づいて作成したコードは次のとおりです。
_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)
}
}
}
_
ラッパークラス(scala.collection.jcl.MutableIterator.Wrapper
)。だからあなたが定義するなら
implicit def javaIteratorToScalaIterator[A](it : Java.util.Iterator[A]) = new Wrapper(it)
その後、Scalaイテレータのサブクラスとして機能するため、foreach
を実行できます。
Scala 2.8の時点で、あなたがしなければならないことは、適切な変換をすでに宣言しているJavaConversionsオブジェクトをインポートすることだけです。
import scala.collection.JavaConversions._
ただし、これは以前のバージョンでは機能しません。
編集: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です)
ここでの正しい答えは、JavaのIterator
から何らかのカスタム型への暗黙的な変換を定義することです。この型は、基礎となるforeach
に委任するIterator
メソッドを実装する必要があります。これにより、Scala= for
- loopと任意のJava Iterator
。]を使用できます。
Scala 2.10:
// Feature warning if you don't enable implicit conversions...
import scala.language.implicitConversions
import scala.collection.convert.WrapAsScala.enumerationAsScalaIterator
Scala 2.10.4+(およびそれ以前))を使用すると、scala.collection.JavaConversionsをインポートすることにより、暗黙的にJava.util.Iterator [A]をscala.collection.Iterator [A]に変換できます。 .asScalaIterator。次に例を示します。
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
}
}
Javaコレクションを配列に変換し、それを使用できます。
val array = Java.util.Arrays.asList("one","two","three").toArray
array.foreach(println)
または、配列をScalaリストに変換します:
val list = List.fromArray(array)
大規模なデータセットを反復処理する場合、.asScala
暗黙的変換を使用してコレクション全体をメモリにロードすることは望ましくないでしょう。この場合、便利な方法はscala.collection.Iterator
traitを実装することです
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はそれほど冗長ではありません:)
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。