Scala

9

'daki koleksiyonların tahsihi koleksiyonlarını aktarma Sıklıkla Scala'da bir "dikdörtgen" koleksiyon koleksiyonunu transpoze etmek zorundayım, örneğin: bir harita listesi, bir harita listesi, bir harita haritası, bir dizi liste , kümeler haritası vb. Koleksiyonlar, belirli bir alandan bir ortak alan adına eşleme olarak eş dağılımlı olarak görülebildiğinden (örneğin: Bir Liste [A]/Array [A], İnt etki alanından A co- etki alanı, [A] ayarı A etki alanından Boole etki alanlarına eşleme, vb.), bir dönüşüm işlemi yapmak için temiz, genel bir işlev yazmak istiyorum (örneğin: bir aktarma listesine bir liste döndürün) haritalar listesi). Ancak, sorun yaşıyorum çünkü() operatörünün dışındaki Scala, koleksiyonları soyut olarak eşleme olarak görmek için birleşik bir API'ye sahip değil gibi görünüyor.Scala

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

biri bana devrik bir jenerik toplama-of-the koleksiyonları içine bu yöntemleri birleştirmeye yardımcı olabilir:

Yani şöyle koleksiyonu-of-the koleksiyonları her türü için ayrı devrik yazmaya son? Ayrıca bana yardımcı olacak (ve eminim diğerleri) bu süreçte bazı yararlı Scala özelliklerini öğrenecekler.

ps: Özel durum işleyişini görmezden geldim ve koleksiyonların koleksiyon koleksiyonunun dikdörtgen olduğunu varsayalım, yani tüm iç koleksiyonların etki alanı öğeleri aynı kümeyi oluşturuyor.

cevap

8

Tür sınıflarını kullanan aşağıdaki dağınık sürümün çok fazla temizlenebileceğinden eminim, ancak hızlı bir kavram kanıtı olarak çalışıyor. (Ben bu mümkün eminim) sağ bağımlı yöntem türleri olmadan dönüş türlerini almak için kolay bir yol göremiyorum, bu yüzden -Xexperimental kullanmak gerekecektir: Bazı testler için

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

Ve şimdi:

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

İstenildiği gibi çalışıyor.

+0

Teşekkürler - bu çok yararlı! Ne yaptığınızı anlamak için epey zamanımı aldı çünkü kullandığınız Scala'nın bazı gelişmiş özelliklerine aşina değilim (bu özellikleri şimdi daha ayrıntılı olarak öğrenmek benim için büyük bir bahane!). – Ashwin