1

Answers to this question do a good job of explaining how to use Scala's Java Converters to change a Java List into a Scala List. Unfortunately, I need to convert a List of Lists from Java to Scala types, and that solution doesn't work:

// pseudocode
java.util.List[java.util.List[String]].asScala
  -> scala.collection.immutable.List[java.util.List[String]]

Is there a way to do this conversion without an O(N) iteration over the Java object?

Community
  • 1
  • 1
Cory Klein
  • 51,188
  • 43
  • 183
  • 243
  • Probably it would be possible with (Indexed)Seq, but the immutable.List is a concrete type, so it is not, you have to pay the price in advance (where N is the size of the outer list). – Gábor Bakos Jul 31 '14 at 20:35
  • 3
    Are you sure you need to avoid it? Have you tried `jlistOfjList.asScala.map(_.asScala)`? – Daenyth Jul 31 '14 at 20:47
  • @Cory, so you were just kidding about needing it to be under O(n)? – dhg Aug 01 '14 at 07:40
  • @dhg I definitely should have phrased my question more accurately. What I was wanting to avoid was an ugly `foreach` or iteration, as I'm used to coming from Java and C++. I wasn't even aware something as elegant as `jlistOfjList.asScala.map(_.asScala)` was even possible in Scala. I should have said I wanted an *elegant* solution, not one that avoids O(N) iteration. In short, no, I was not kidding, I just misexpressed my intentions. – Cory Klein Aug 01 '14 at 15:26
  • @CoryKlein Learn to use map. It's (imo) the basic building block that distinguishes functional programming from other styles – Daenyth Aug 14 '14 at 20:21

2 Answers2

3

You need to convert the nested lists as well, but that would require the up front O(n):

import scala.collection.JavaConverters._

val javaListOfLists = List(List("a", "b", "c").asJava, List("d", "e", "f").asJava).asJava
val scalaListOfLists = javaListOfLists.asScala.toList.map(_.asScala.toList)

Alternatively, you could convert the outer list into a Stream[List[T]], that would only apply the conversion cost as you accessed each item

val scalaStreamOfLists = javaListOfLists.asScala.toStream.map(_.asScala.toList)

If you don't want to pay the conversion cost at all, you could write a wrapper around java.util.List which would give you a scala collection interface. a rought shot at that would be:

def wrap[T](javaIterator: java.util.Iterator[T]): Stream[T] = {
  if (javaIterator.hasNext)
    javaIterator.next #:: wrap(javaIterator)
  else
    empty
}

val outerWrap = wrap(javaListOfLists.iterator).map(inner => wrap(inner.iterator()))
Angelo Genovese
  • 3,398
  • 17
  • 23
0

alternatively you can use scalaj-collection library i wrote specifically for this purpose

import com.daodecode.scalaj.collection._

val listOfLists: java.util.List[java.util.List[String]] = ...
val s: mutable.Seq[mutable.Seq[String]] = listOfLists.deepAsScala

that's it. It will convert all nested java collections and primitive types to scala versions. You can also convert directly to immutable data structures using deepAsScalaImmutable (with some copying overhead of course)

Eugene Platonov
  • 3,145
  • 3
  • 26
  • 20