Durchlaufen von Java-Sammlungen in Scala


113

Ich schreibe einen Scala-Code, der die Apache POI- API verwendet. Ich möchte über die Zeilen iterieren, die in java.util.Iteratorder Sheet-Klasse enthalten sind. Ich möchte den Iterator in einer for eachStilschleife verwenden, daher habe ich versucht, ihn in eine native Scala-Sammlung zu konvertieren, werde aber kein Glück haben.

Ich habe mir die Scala-Wrapper-Klassen / -Eigenschaften angesehen, kann aber nicht sehen, wie man sie richtig verwendet. Wie iteriere ich über eine Java-Sammlung in Scala, ohne den ausführlichen while(hasNext()) getNext()Stil der Schleife zu verwenden?

Hier ist der Code, den ich basierend auf der richtigen Antwort geschrieben habe:

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

Ich kann die Zeile "for (val row <- rows) {" scheinbar nicht einfügen, ohne dass der Parser denkt, dass das Zeichen '<' ein XML-Abschluss-Tag ist. Die Backticks funktionieren nicht
BefittingTheorem

Sie sollten in der Lage sein, implizit in IteratirWrapper zu konvertieren, wodurch Sie ein gutes Stück Syntax sparen. Google für implizite Conversions in Scala.
Daniel Spiewak

Antworten:


28

Es gibt eine Wrapper-Klasse ( scala.collection.jcl.MutableIterator.Wrapper). Also, wenn Sie definieren

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

Dann fungiert es als Unterklasse des Scala-Iterators, sodass Sie dies tun können foreach.


Es sollte lauten: scala.collection.jcl.MutableIterator.Wrapper
samg

37
Diese Antwort ist in Scala 2.8 veraltet. siehe stackoverflow.com/questions/2708990/…
Alex R

256

Ab Scala 2.8 müssen Sie lediglich das JavaConversions-Objekt importieren, das bereits die entsprechenden Konvertierungen deklariert.

import scala.collection.JavaConversions._

Dies funktioniert jedoch in früheren Versionen nicht.


24

Bearbeiten : Scala 2.13.0 ist veraltet scala.collection.JavaConverters, daher müssen Sie seit 2.13.0 verwenden scala.jdk.CollectionConverters.

Scala 2.12.0 ist veraltet scala.collection.JavaConversions. Seit 2.12.0 wäre eine Möglichkeit, dies zu tun, etwa:

import scala.collection.JavaConverters._

// ...

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

(Beachten Sie den Import, neu ist JavaConverters, veraltet ist JavaConversions)


2
Ich suchte nach "toScala" ^ _ ^!
Profiterole

15

Die richtige Antwort besteht darin, eine implizite Konvertierung von Java Iteratorin einen benutzerdefinierten Typ zu definieren. Dieser Typ sollte eine foreachMethode implementieren , die an den Basiswert delegiert Iterator. Auf diese Weise können Sie eine Scala- forSchleife mit jedem Java verwenden Iterator.


9

Für Scala 2.10:

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

5

Mit Scala 2.10.4+ (und möglicherweise früher) ist es möglich, java.util.Iterator [A] implizit in scala.collection.Iterator [A] zu konvertieren, indem scala.collection.JavaConversions.asScalaIterator importiert wird. Hier ist ein Beispiel:

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

Sie können die Java-Sammlung in ein Array konvertieren und Folgendes verwenden:

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

Oder konvertieren Sie das Array in eine Scala-Liste:

val list = List.fromArray(array)

4

Wenn Sie ein großes Dataset durchlaufen, möchten Sie wahrscheinlich nicht die gesamte Sammlung mit .asScalaimpliziter Konvertierung in den Speicher laden . In diesem Fall besteht ein praktischer Ansatz darin, scala.collection.IteratorMerkmale zu implementieren

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

Es hat ein ähnliches Konzept, aber weniger ausführlich IMO :)


2

Wenn Sie die Implikationen in scala.collection.JavaConversions vermeiden möchten, können Sie scala.collection.JavaConverters verwenden , um explizit zu konvertieren.

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

Beachten Sie die Verwendung der asScalaMethode zum Konvertieren von Java Iteratorin eine Scala Iterator.

Die JavaConverter sind seit Scala 2.8.1 verfügbar.


Ich habe import scala.collection.JavaConverters._ und dann javaList.iterator().asScala von Ihrem Beispiel und es hat funktioniert
kosiara - Bartosz Kosarzycki
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.