2010-02-13 22 views
16

आप परिवर्तित एकजावा/स्काला (गहरी) संग्रह अंतर

java.util.HashMap[ 
    java.lang.String, java.util.ArrayList[ 
     java.util.ArrayList[java.lang.Double] 
    ] 
] 
(all of the objects are from java.util or java.lang) 

Map[ 
    String, Array[ 
     Array[Double] 
    ] 
] 
(all of the objects are from scala) 

को धन्यवाद, की सबसे खूबसूरत और/या प्रभावी तरीका है क्या पर अपने विचार साझा करें कृपया सकते हैं - एक

+0

क्या यह एक और अधिक डिज़ाइन समस्या नहीं है? इस संरचना का अर्थशास्त्र क्या है? आप वस्तुओं को कन्वर्ट क्यों करना चाहते हैं? –

+0

असल में मैं जैक्सन जेसन लाइब्रेरी के माध्यम से एक जेसन फ़ाइल से यह डेटा पढ़ रहा हूं (मैंने कोशिश की कि एसजेसन और लिफ्ट-जेसन दोनों ने मुझे असफल कर दिया)। जैक्सन जेसन के पास स्कैला एपीआई नहीं है इसलिए मैंने नौकरी करने के लिए जावा एपीआई का इस्तेमाल किया। –

उत्तर

7

ऐसा करने की विधि 2.7 से 2.8 तक बदल गई है। पुनः नाम की विधि 2.8 के लिए अच्छी तरह से काम करती है। 2.7 के लिए, यदि आप इसके बजाए तरह collections.jcl का उपयोग करेंगे:

object Example { 
    import scala.collection.jcl 

    // Build the example data structure 
    val row1 = new java.util.ArrayList[Double]() 
    val row2 = new java.util.ArrayList[Double]() 
    val mat = new java.util.ArrayList[java.util.ArrayList[Double]]() 
    row1.add(1.0) ; row1.add(2.0) ; row2.add(3.0) ; row2.add(4.0) 
    mat.add(row1) ; mat.add(row2) 
    val named = new java.util.HashMap[String,java.util.ArrayList[java.util.ArrayList[Double]]] 
    named.put("matrix",mat) 

    // This actually does the conversion 
    def asScala(thing: java.util.HashMap[String,java.util.ArrayList[java.util.ArrayList[Double]]]) = { 
    Map() ++ (new jcl.HashMap(thing)).map(kv => { 
     (kv._1 , 
     (new jcl.ArrayList(kv._2)).map(al => { 
      (new jcl.ArrayList(al)).toArray 
     }).toArray 
    ) 
    }) 
    } 
} 

तो, सामान्य विचार यह है: बाहर से, एक स्काला बराबर में जावा संग्रह लपेट, तो मानचित्र का उपयोग अगले में सब कुछ रैप करने के लिए स्तर। यदि आप स्कैला प्रस्तुतियों के बीच कनवर्ट करना चाहते हैं, तो इसे बाहर करें (यहां, .toArray सिरों पर)।

और यहाँ आप उदाहरण काम कर देख सकते हैं:

scala> Example.named 
res0: java.util.HashMap[String,java.util.ArrayList[java.util.ArrayList[Double]]] = {matrix=[[1.0, 2.0], [3.0, 4.0]]} 

scala> val sc = Example.asScala(Example.named) 
sc: scala.collection.immutable.Map[String,Array[Array[Double]]] = Map(matrix -> Array([[email protected], [[email protected])) 

scala> sc("matrix")(0) 
res1: Array[Double] = Array(1.0, 2.0) 

scala> sc("matrix")(1) 
res2: Array[Double] = Array(3.0, 4.0) 
13

मैं दावा नहीं कर रहा हूं कि यह सब सुरुचिपूर्ण है, लेकिन यह काम करता है। मैं थोड़ा सा मदद करने के लिए टाइप अनुमान को अनुमति देने के लिए स्पष्ट रूप से JavaConversions से रूपांतरणों का उपयोग करता हूं। JavaConversions स्कैला 2.8 में नया है।

import collection.JavaConversions._ 
import java.util.{ArrayList, HashMap} 
import collection.mutable.Buffer 

val javaMutable = new HashMap[String, ArrayList[ArrayList[Double]]] 

val scalaMutable: collection.Map[String, Buffer[Buffer[Double]]] = 
    asMap(javaMutable).mapValues(asBuffer(_).map(asBuffer(_))) 

val scalaImmutable: Map[String, List[List[Double]]] = 
    Map(asMap(javaMutable).mapValues(asBuffer(_).map(asBuffer(_).toList).toList).toSeq: _*) 

अद्यतन: यहाँ एक वैकल्पिक दृष्टिकोण implicits का उपयोग करता है एक मनमाने ढंग से आंतरिक संरचना करने के लिए रूपांतरण के एक सेट लागू करने के लिए है।

trait ==>>[A, B] extends (A => B) { 
    def apply(a: A): B 
} 

object ==>> { 
    def convert[A, B](a: A)(implicit a2b: A ==>> B): B = a 

    // the default identity conversion 
    implicit def Identity_==>>[A] = new (A ==>> A) { 
    def apply(a: A) = a 
    } 

    // import whichever conversions you like from here: 
    object Conversions { 
    import java.util.{ArrayList, HashMap} 
    import collection.mutable.Buffer 
    import collection.JavaConversions._ 

    implicit def ArrayListToBuffer[T, U](implicit t2u: T ==>> U) = new (ArrayList[T] ==>> Buffer[U]) { 
     def apply(a: ArrayList[T]) = asBuffer(a).map(t2u) 
    } 

    implicit def HashMapToMap[K, V, VV](implicit v2vv: V ==>> VV) = new (HashMap[K, V] ==>> collection.Map[K, VV]) { 
     def apply(a: java.util.HashMap[K, V]) = asMap(a).mapValues(v2vv) 
    } 
    } 
} 

object test { 
    def main(args: Array[String]) { 

    import java.util.{ArrayList, HashMap} 
    import collection.mutable.Buffer 

    // some java collections with different nesting 
    val javaMutable1 = new HashMap[String, ArrayList[ArrayList[Double]]] 
    val javaMutable2 = new HashMap[String, ArrayList[HashMap[String, ArrayList[ArrayList[Double]]]]] 

    import ==>>.{convert, Conversions} 
    // here comes the elegant part! 
    import Conversions.{HashMapToMap, ArrayListToBuffer} 
    val scala1 = convert(javaMutable1) 
    val scala2 = convert(javaMutable2) 

    // check the types to show that the conversion worked. 
    scala1: collection.Map[String, Buffer[Buffer[Double]]] 
    scala2: collection.Map[String, Buffer[collection.Map[String, Buffer[Buffer[Double]]]]] 
    } 
} 
3

@ retronym का जवाब अच्छा है अगर अपने संग्रह समरूप हैं, लेकिन यह जब मैं एक मिश्रित संग्रह था मेरे लिए काम करने के लिए नहीं मालूम था। उदाहरण के लिए:

val x = Map(5 -> Array(1, List(2, 7), 3), 6 -> Map(5 -> List(7, 8, 9)))

जावा के लिए इस तरह के एक संग्रह को परिवर्तित करने के लिए आप क्रम प्रकार पर भरोसा करने की जरूरत है क्योंकि x के प्रकार के कुछ है कि रिकर्सिवली संकलन समय पर जावा में बदला जा सकता है।

def convert(x:Any):Any = 
    { 
    import collection.JavaConversions._ 
    import collection.JavaConverters._ 
    x match 
    { 
     case x:List[_] => x.map{convert}.asJava 
     case x:collection.mutable.ConcurrentMap[_, _] => x.mapValues(convert).asJava 
     case x:collection.mutable.Map[_, _] => x.mapValues(convert).asJava 
     case x:collection.immutable.Map[_, _] => x.mapValues(convert).asJava 
     case x:collection.Map[_, _] => x.mapValues(convert).asJava 
     case x:collection.mutable.Set[_] => x.map(convert).asJava 
     case x:collection.mutable.Buffer[_] => x.map(convert).asJava 
     case x:Iterable[_] => x.map(convert).asJava 
     case x:Iterator[_] => x.map(convert).asJava 
     case x:Array[_] => x.map(convert).toArray 
     case _ => x 
    } 
    } 

ऐसा ही एक विधि जावा से स्केला को परिवर्तित करने के लिए लिखा जा सकता है: यहाँ एक विधि है कि जावा के लिए मिश्रित स्केला संग्रह परिवर्तित संभाल सकता है।

ध्यान दें कि इस विधि का वापसी प्रकार Any है, इसलिए लौटाए गए मान का उपयोग करने के लिए, आपको एक कलाकार: val y = convert(x).asInstanceOf[java.util.Map[Int, Any]] करना पड़ सकता है।

संबंधित मुद्दे