Итерация по коллекциям Java в Scala
Я пишу некоторый код Scala, который использует Apache POI API. Я хотел бы перебрать строки, содержащиеся в java.util.Iterator что я получаю из листа класса. Я хотел бы использовать итератор в for each цикл стиля, поэтому я пытался преобразовать его в родную коллекцию Scala, но не повезло.
Я посмотрел на классы/черты оболочки Scala, но я не вижу, как их правильно использовать. Как я могу перебирать коллекцию Java в Scala без используя многословный while(hasNext()) getNext() стиль петли?
вот код, который я написал на основе правильный ответ:
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)
}
}
}
9 ответов:
есть класс-оболочка (
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._Это не будет работать, хотя в предыдущих версиях.
правильный ответ здесь-определить неявное преобразование из Java в
Iteratorк некоторому пользовательскому типу. Этот тип должен реализовывать aforeachметод, который делегирует к основнойIterator. Это позволит вам использовать Scalafor-цикл с любой JavaIterator.
Для Scala 2.10:
// Feature warning if you don't enable implicit conversions... import scala.language.implicitConversions import scala.collection.convert.WrapAsScala.enumerationAsScalaIterator
Scala 2.12.0 осуждает
scala.collection.JavaConversions, Так что с 2.12.0 один из способов сделать это будет что-то вроде:import scala.collection.JavaConverters._ // ... for(k <- javaCollection.asScala) { // ... }(обратите внимание на импорт, new-JavaConverters, deprecated-JavaConversions)
С помощью Scala 2.10.4+ (и, возможно, ранее) можно неявно конвертировать java.утиль.Итератор[A] в scala.коллекция.Итератор[A] путем импорта scala.коллекция.JavaConversions.асскалайтер. Вот пример:
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признак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 :)
если вы хотите, чтобы избежать неявные преобразования в скала.коллекция.JavaConversions можно использовать скала.коллекция.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метод для преобразования JavaIteratorк скалеIterator.JavaConverters были доступны с Scala 2.8.1.
Comments