Scala'da Java koleksiyonları üzerinde yineleme


113

Kullanan bir Scala kodu yazıyorum Apache POI API'sini . java.util.IteratorSheet sınıfından aldığım satırların içerdiği satırları yinelemek istiyorum . Yineleyiciyi bir for eachstil döngüsünde kullanmak istiyorum , bu yüzden onu yerel bir Scala koleksiyonuna dönüştürmeye çalışıyorum ama şansım olmayacak.

Scala sarmalayıcı sınıflarına / özelliklerine baktım, ancak bunları nasıl doğru kullanacağımı göremiyorum. Ayrıntılı while(hasNext()) getNext()döngü stilini kullanmadan Scala'da bir Java koleksiyonunu nasıl yineleyebilirim ?

İşte doğru cevaba göre yazdığım kod:

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

Ayrıştırıcı '<' karakterinin bir XML kapanış etiketi olduğunu düşünmeden "for (val row <- rows) {" satırını dahil edemiyorum. Ters işaretler çalışmıyor
BefittingTheorem

IteratirWrapper'a örtük olarak dönüştürebilmelisiniz, bu da size biraz sözdizimi tasarrufu sağlar. Scala'da örtük dönüşümler için Google.
Daniel Spiewak

Yanıtlar:


28

Bir sarmalayıcı sınıfı ( scala.collection.jcl.MutableIterator.Wrapper) var. Yani tanımlarsan

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

daha sonra bunu yapabilmeniz için Scala yineleyicinin bir alt sınıfı olarak hareket edecektir foreach.


Bunu şöyle olmalıdır: scala.collection.jcl.MutableIterator.Wrapper
samg

37
Bu cevap Scala 2.8'de kullanılmamaktadır; bakınız stackoverflow.com/questions/2708990/…
Alex R

256

Scala 2.8'den itibaren, yapmanız gereken tek şey, uygun dönüştürmeleri zaten bildiren JavaConversions nesnesini içe aktarmaktır.

import scala.collection.JavaConversions._

Bu, önceki sürümlerde çalışmayacaktır.


24

Düzenleme : Scala 2.13.0 kullanımdan kaldırılıyor scala.collection.JavaConverters, bu nedenle 2.13.0'dan beri kullanmanız gerekiyor scala.jdk.CollectionConverters.

Scala 2.12.0 kullanımdan kaldırılıyor scala.collection.JavaConversions , bu nedenle 2.12.0'dan beri bunu yapmanın bir yolu şöyle olabilir:

import scala.collection.JavaConverters._

// ...

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

(içe aktarmaya dikkat edin, yeni JavaConverters, kullanımdan kaldırılan JavaConversions)


2
"ToScala" yı arıyordum ^ _ ^!
Profiterol

15

Buradaki doğru cevap, Java'lardan Iteratorözel bir türe örtük bir dönüşüm tanımlamaktır . Bu tür foreach, temelini temsil eden bir yöntem uygulamalıdır Iterator. Bu, forherhangi bir Java ile bir Scala döngüsü kullanmanıza izin verecektir Iterator.


9

Scala 2.10 için:

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

5

Scala 2.10.4+ (ve muhtemelen daha eski) ile scala.collection.JavaConversions.asScalaIterator'ı içe aktararak java.util.Iterator [A] 'ı scala.collection.Iterator [A]' ya örtük olarak dönüştürmek mümkündür. İşte bir örnek:

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 koleksiyonunu bir diziye dönüştürebilir ve bunu kullanabilirsiniz:

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

Veya devam edin ve diziyi bir Scala listesine dönüştürün:

val list = List.fromArray(array)

4

Büyük bir veri kümesinde yineleme yapıyorsanız, muhtemelen tüm koleksiyonu .asScalaörtük dönüştürme ile belleğe yüklemek istemezsiniz . Bu durumda, kullanışlı bir yaklaşım, scala.collection.Iteratorözelliği uygulamaktır.

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

Benzer bir konsepte sahip ancak daha az ayrıntılı IMO :)


2

Scala.collection.JavaConversions içindeki sonuçlardan kaçınmak istiyorsanız, açıkça dönüştürmek için scala.collection.JavaConverters'ı kullanabilirsiniz .

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

asScalaJava'yı IteratorScala'ya dönüştürmek için yöntemin kullanımına dikkat edin Iterator.

JavaConverters, Scala 2.8.1'den beri mevcuttur.


Kullandım import scala.collection.JavaConverters._ ve sonra javaList.iterator().asScala sizin örneğinizden ve işe yaradı
kosiara - Bartosz Kosarzycki
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.