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) {"줄을 포함 할 수없는 것 같습니다. 백틱이 작동하지 않습니다
BefittingTheorem

암시 적으로 IteratirWrapper로 변환 할 수 있어야 구문이 상당히 절약됩니다. Scala에서 암시 적 변환을위한 Google.
Daniel Spiewak

답변:


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 2009

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.JavaConverters2.13.0부터 사용해야 scala.jdk.CollectionConverters합니다.

Scala 2.12.0은 더 이상 사용되지 않으므로 scala.collection.JavaConversions2.12.0부터이 작업을 수행하는 한 가지 방법은 다음과 같습니다.

import scala.collection.JavaConverters._

// ...

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

(가져 오기에 유의하십시오. new는 JavaConverters, 더 이상 사용되지 않는 것은 JavaConversions입니다)


2
나는 "toScala"를 찾고 있었다 ^ _ ^!
Profiterole

15

여기서 정답은 Java에서 Iterator일부 사용자 정의 유형으로 의 암시 적 변환을 정의하는 것 입니다. 이 형식은 foreach기본 .NET Framework에 위임 하는 메서드를 구현해야합니다 Iterator. 이를 통해 forJava와 함께 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 - 바르 토스 Kosarzycki을
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.