9

में मनमानी संग्रह-संग्रह का स्थानांतरण करना मुझे अक्सर स्कैला में "आयताकार" संग्रह-संग्रह का स्थानांतरण करना पड़ता है, उदाहरण के लिए: मानचित्रों की एक सूची, सूचियों का नक्शा, मानचित्र का मानचित्र, सूचियों का एक सेट , सेट का नक्शा इत्यादि। चूंकि संग्रह को एक विशिष्ट डोमेन से एक सह-डोमेन में मैपिंग के रूप में समान रूप से देखा जा सकता है (उदाहरण: एक सूची [ए]/ऐरे [ए] इंट डोमेन से एक सह- डोमेन, सेट [ए] एक डोमेन से बूलियन सह-डोमेन इत्यादि में मैपिंग है), मैं एक ट्रांज़ेक्शन ऑपरेशन करने के लिए एक स्वच्छ, जेनेरिक फ़ंक्शन लिखना चाहता हूं (उदाहरण के लिए: सूचियों के मानचित्र को ट्रांसपोज़ में बदलें मानचित्रों की सूची)। हालांकि, मुझे परेशानी हो रही है क्योंकि() ऑपरेटर के अलावा, स्कैला में मैपिंग के रूप में संग्रह को देखने के लिए एक एकीकृत API नहीं लगता है?स्कैला

तो मैं अंत में इस प्रकार संग्रह के- संग्रह के प्रत्येक प्रकार के लिए एक अलग पक्षांतरित लेखन:

def transposeMapOfLists[A,B](mapOfLists: Map[A,List[B]]) : List[Map[A,B]] = { 
    val k = (mapOfLists keys) toList 
    val l = (k map { mapOfLists(_) }) transpose; 
    l map { v => (k zip v) toMap } 
} 

def transposeListOfMaps[A,B](listOfMaps: List[Map[A,B]]) : Map[A,List[B]] = { 
    val k = (listOfMaps(0) keys) toList 
    val l = (listOfMaps map { m => k map { m(_) } }) transpose; 
    (k zip l) toMap 
} 

def transposeMapOfMaps[A,B,C](mapOfMaps: Map[A,Map[B,C]]) : Map[B,Map[A,C]] = { 
    val k = (mapOfMaps keys) toList 
    val listOfMaps = k map { mapOfMaps(_) } 
    val mapOfLists = transposeListOfMaps(listOfMaps) 
    mapOfLists map { p => (p._1, (k zip p._2) toMap) } 
} 

किसी की मदद कर सकते हैं मुझे एक सामान्य संग्रह के- संग्रह में इन तरीकों को एकजुट स्थानांतरित? यह मेरी मदद करेगा (और मुझे यकीन है कि दूसरों) प्रक्रिया में कुछ उपयोगी स्काला सुविधाओं को सीखेंगे।

ps: मैंने अपवाद हैंडलिंग को अनदेखा कर लिया है और माना है कि इनपुट संग्रह-संग्रह संग्रह आयताकार है, यानी, सभी आंतरिक संग्रह 'डोमेन तत्व एक ही सेट का गठन करते हैं।

उत्तर

8

मुझे यकीन है कि टाइप क्लास का उपयोग करके निम्नलिखित गन्दा संस्करण को साफ़ किया जा सकता है, लेकिन यह त्वरित प्रमाण-अवधारणा के रूप में कार्य करता है। मैं (मुझे यकीन है कि यह संभव है हूँ) सही निर्भर विधि प्रकार के बिना वापसी प्रकार प्राप्त करने के लिए एक आसान तरीका नहीं दिख रहा है, तो आप -Xexperimental का उपयोग करना होगा:

trait Mapping[A, B, C] { 
    type M[D] <: PartialFunction[A, D] 
    def domain(c: C): Seq[A] 
    def fromPairs[D](ps: Seq[(A, D)]): M[D] 
    def codomain(c: C)(implicit ev: C <:< PartialFunction[A, B]) = 
    domain(c).map(c) 
    def toPairs(c: C)(implicit ev: C <:< PartialFunction[A, B]) = 
    domain(c).map(a => (a, c(a))) 
} 

implicit def seqMapping[A, B <: Seq[A]] = new Mapping[Int, A, B] { 
    type M[C] = Seq[C] 
    def domain(c: B) = 0 until c.size 
    def fromPairs[C](ps: Seq[(Int, C)]) = ps.sortBy(_._1).map(_._2) 
} 

implicit def mapMapping[A, B, C <: Map[A, B]] = new Mapping[A, B, C] { 
    type M[D] = Map[A, D] 
    def domain(c: C) = c.keys.toSeq 
    def fromPairs[D](ps: Seq[(A, D)]) = ps.toMap 
} 

def transpose[A, B, C, M, N](m: M)(implicit 
    pev: M <:< PartialFunction[A, N], 
    qev: N <:< PartialFunction[B, C], 
    mev: Mapping[A, N, M], 
    nev: Mapping[B, C, N] 
) = nev.fromPairs(nev.domain(mev.codomain(m).head).map(b => 
    b -> mev.fromPairs(mev.toPairs(m).map { case (a, c) => a -> c(b) }) 
)) 

और अब कुछ परीक्षण के लिए:

scala> println(transpose(List(Map("a" -> 1, "b" -> 13), Map("b" -> 99, "a" -> 14)))) 
Map(a -> Vector(1, 14), b -> Vector(13, 99)) 

scala> println(transpose(Map('a' -> List(1, 2, 3), 'z' -> List(4, 5, 6)))) 
Vector(Map(a -> 1, z -> 4), Map(a -> 2, z -> 5), Map(a -> 3, z -> 6)) 

scala> println(transpose(Map("x" -> Map(4 -> 'a, 99 -> 'z), "y" -> Map(4 -> 'b, 99 -> 's)))) 
Map(4 -> Map(x -> 'a, y -> 'b), 99 -> Map(x -> 'z, y -> 's)) 

तो यह वांछित के रूप में काम कर रहा है।

+0

धन्यवाद - यह बहुत उपयोगी है! आपने यह समझने में काफी समय लगाया कि आपने क्या किया है क्योंकि मैं आपके द्वारा उपयोग की जाने वाली स्कैला की कुछ उन्नत विशेषताओं से परिचित नहीं हूं (अब इन सुविधाओं को और अधिक विस्तार से सीखना मेरे लिए बहुत अच्छा बहाना है!)। – Ashwin