Pytanie Jak przekonwertować zagnieżdżoną kolekcję scala do zagnieżdżonej kolekcji Java


Mam problemy z kompilacją między Scala i Javą.

Mój kod Java wymaga

java.util.Map<Double, java.lang.Iterable<Foo>>

Mój kod scala ma

Map[Double, Vector[Foo]]

Dostaję błąd kompilacji:

error: type mismatch;
found   : scala.collection.immutable.Map[scala.Double,Vector[Foo]
required: java.util.Map[java.lang.Double,java.lang.Iterable[Foo]]

Wygląda na to, że scala.collection.JavaConversions nie mają zastosowania do zagnieżdżonych kolekcji, mimo że wektor może zostać nieodwracalnie przekształcony w Iterable. Bez iteracji przez kolekcję scala i robienia konwersji ręcznie, czy jest coś, co mogę zrobić, aby typy działały?


16
2017-12-20 23:09


pochodzenie




Odpowiedzi:


scala.collection.JavaConversions powinien być przestarzały IMHO. Lepiej być świadomym, gdzie i kiedy następuje konwersja przy użyciu scala.collection.JavaConverters. W Twoim przypadku:

import scala.collection.JavaConverters._

type Foo = Int // Just to make it compile
val scalaMap = Map(1.0 -> Vector(1, 2)) // As an example

val javaMap = scalaMap.map { 
  case (d, v) => d -> v.toIterable.asJava
}.asJava

7
2017-12-20 23:30



Dziękuję za skierowanie mnie do JavaConversions. Nie wiedziałem o tym. Potrzebowałem również trochę nieprzyjemnego Java Generics Wildcarding dla mojej metody, aby uzyskać działanie typów zwrotów, tzn. Przekształcenie zadeklarowanego typu powrotu na publiczny <T extends Iterable <Foo >> Map <Double, T> createMap () - Adam K


Napisałem tę funkcję ogólnego przeznaczenia, która działa dobrze na moje potrzeby.

def toJava(x: Any): Any = {
  import scala.collection.JavaConverters._
  x match {
    case y: scala.collection.MapLike[_, _, _] => 
      y.map { case (d, v) => toJava(d) -> toJava(v) } asJava
    case y: scala.collection.SetLike[_,_] => 
      y map { item: Any => toJava(item) } asJava
    case y: Iterable[_] => 
      y.map { item: Any => toJava(item) } asJava
    case y: Iterator[_] => 
      toJava(y.toIterable)
    case _ => 
      x
  }
}

3
2017-09-03 16:01



Miły! Zastanawiam się również, czy napisałeś podobną funkcję rekurencyjną doScala ... - vishvAs vAsuki
'' 'Funkcja rekurencyjna toScala zakończyła się pisaniem: def doScala (x: Any): Any = {import collection.JavaConversions._ x match {case y: java.util.Map [, _] => mapAsScalaMap (y) .map {case (d, v) => toScala (d) -> toScala (v)} case y: java.lang.Iterable [] => iterableAsScalaIterable (y) .toList.map {item: Any => toScala (element)} case y: java.util.Iterator [_] => toScala (y) case _ => x}} '' ' - vishvAs vAsuki
Oddzielnie zamieściłem pokrewne pytanie tutaj: stackoverflow.com/questions/43462034/... - vishvAs vAsuki


To lepiej pasuje do moich potrzeb:

  def toJava(m: Any): Any = {
    import java.util
    import scala.collection.JavaConverters._
    m match {
      case sm: Map[_, _] => sm.map(kv => (kv._1, toJava(kv._2))).asJava
      case sl: Iterable[_] => new util.ArrayList(sl.map( toJava ).asJava.asInstanceOf[util.Collection[_]])
      case _ => m
    }
  }

3
2017-11-18 13:21





Spróbuj tego, jeśli ktoś szuka rozwiązania w iskrze scala,

import org.apache.spark.sql.catalyst.expressions.GenericRowWithSchema

Tutaj, y jest zagnieżdżony WrapperArray

y match {
          case x : WrappedArray[x] =>
             (x.map(f => f match {case z: GenericRowWithSchema => z.mkString(",").toString()
                                                case z:Any => z  })).asJavaCollection
          case _ => row.get(i).asInstanceOf[Object]
        }

Powyższy kod, robi dwie rzeczy, 1) Jeśli Array opakowania ma prymitywny typ danych, warunek case_ przechodzi przez 2) Jeśli opakowanie Array ma typ danych złożonych (np. Rozpórki), wykonywany jest case GenericRowWithSchema.


0
2017-12-28 12:06