web-dev-qa-db-ja.com

JavaのコレクションScala

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

ラッパークラス(scala.collection.jcl.MutableIterator.Wrapper)。だからあなたが定義するなら

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

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

26
James

Scala 2.8の時点で、あなたがしなければならないことは、適切な変換をすでに宣言しているJavaConversionsオブジェクトをインポートすることだけです。

import scala.collection.JavaConversions._

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

251
ttonelli

編集: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です)

16
antonone

ここでの正しい答えは、JavaのIteratorから何らかのカスタム型への暗黙的な変換を定義することです。この型は、基礎となるforeachに委任するIteratorメソッドを実装する必要があります。これにより、Scala= for- loopと任意のJava Iterator。]を使用できます。

15
Daniel Spiewak

Scala 2.10:

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

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
  }

}
5
user4322779

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

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

または、配列をScalaリストに変換します:

val list = List.fromArray(array)
4
Fabian Steeg

大規模なデータセットを反復処理する場合、.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はそれほど冗長ではありません:)

3
Max

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。

2
kilo