Lặp lại các bộ sưu tập Java trong Scala


113

Tôi đang viết một số mã Scala sử dụng API Apache POI . Tôi muốn lặp lại các hàng có trong hàng java.util.Iteratormà tôi nhận được từ lớp Trang tính. Tôi muốn sử dụng trình vòng lặp trong một for eachvòng lặp kiểu, vì vậy tôi đã cố gắng chuyển đổi nó thành một bộ sưu tập Scala gốc nhưng sẽ không thành công.

Tôi đã xem xét các lớp / đặc điểm của trình bao bọc Scala, nhưng tôi không thể thấy cách sử dụng chúng một cách chính xác. Làm cách nào để lặp lại một tập hợp Java trong Scala mà không sử dụng while(hasNext()) getNext()kiểu vòng lặp dài dòng ?

Đây là mã tôi đã viết dựa trên câu trả lời đúng:

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

Tôi dường như không thể bao gồm dòng "for (val row <- row) {" mà trình phân tích cú pháp nghĩ rằng ký tự '<' là thẻ đóng XML? Các thanh chống lưng không hoạt động
BefittingTheorem

Bạn sẽ có thể chuyển đổi ngầm sang IteratirWrapper, tiết kiệm cho bạn một chút cú pháp. Google cho các chuyển đổi ngầm trong Scala.
Daniel Spiewak

Câu trả lời:


28

Có một lớp wrapper ( scala.collection.jcl.MutableIterator.Wrapper). Vì vậy, nếu bạn xác định

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

thì nó sẽ hoạt động như một lớp con của trình lặp Scala để bạn có thể làm foreach.


Nó nên đọc: scala.collection.jcl.MutableIterator.Wrapper
samg

37
Câu trả lời này đã lỗi thời trong Scala 2.8; xem stackoverflow.com/questions/2708990/…
Alex R

256

Kể từ Scala 2.8, tất cả những gì bạn phải làm là nhập đối tượng JavaConversions, đối tượng này đã khai báo các chuyển đổi thích hợp.

import scala.collection.JavaConversions._

Tuy nhiên, điều này sẽ không hoạt động trong các phiên bản trước.


24

Chỉnh sửa : Scala 2.13.0 không dùng nữa scala.collection.JavaConverters, vì vậy kể từ 2.13.0, bạn cần sử dụng scala.jdk.CollectionConverters.

Scala 2.12.0 không dùng nữa scala.collection.JavaConversions, vì vậy kể từ 2.12.0, một cách để thực hiện việc này sẽ giống như:

import scala.collection.JavaConverters._

// ...

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

(lưu ý nhập, mới là JavaConverters, không dùng nữa là JavaConversions)


2
Tôi đang tìm kiếm "toScala" ^ _ ^!
Profiterole

15

Câu trả lời đúng ở đây là xác định một chuyển đổi ngầm định từ Java Iteratorsang một số kiểu tùy chỉnh. Loại này nên triển khai một foreachphương thức ủy quyền cho cơ sở Iterator. Điều này sẽ cho phép bạn sử dụng Scala for-loop với bất kỳ Java nào Iterator.


9

Đối với Scala 2.10:

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

5

Với Scala 2.10.4+ (và có thể sớm hơn), có thể chuyển đổi ngầm định java.util.Iterator [A] thành scala.collection.Iterator [A] bằng cách nhập scala.collection.JavaConversions.asScalaIterator. Đây là một ví dụ:

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

Bạn có thể chuyển đổi bộ sưu tập Java thành một mảng và sử dụng:

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

Hoặc tiếp tục và chuyển đổi mảng thành danh sách Scala:

val list = List.fromArray(array)

4

Nếu bạn đang lặp qua một tập dữ liệu lớn, thì bạn có thể không muốn tải toàn bộ bộ sưu tập vào bộ nhớ với .asScalachuyển đổi ngầm định. Trong trường hợp này, một cách tiếp cận hữu ích là triển khai scala.collection.Iteratorđặc điểm

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

Nó có khái niệm tương tự nhưng IMO ít dài hơn :)


2

Nếu bạn muốn tránh những hệ lụy trong scala.collection.JavaConversions, bạn có thể sử dụng scala.collection.JavaConverters để chuyển đổi một cách rõ ràng.

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

Lưu ý việc sử dụng asScalaphương pháp này để chuyển đổi Java Iteratorsang Scala Iterator.

Các JavaConverters đã có sẵn kể từ Scala 2.8.1.


Tôi đã sử dụng import scala.collection.JavaConverters._ và sau đó javaList.iterator().asScala từ ví dụ của bạn và nó hoạt động
kosiara - Bartosz Kosarzycki
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.