9

Tôi thường phải chuyển đổi bộ sưu tập "hình chữ nhật" trong Scala, ví dụ: danh sách bản đồ, bản đồ danh sách, bản đồ bản đồ, tập hợp danh sách , một bản đồ các bộ vv Vì các bộ sưu tập có thể được xem như một ánh xạ từ một miền cụ thể tới một miền đồng (ví dụ: một List [A]/Array [A] là một ánh xạ từ miền Int đến A co- tên miền, Đặt [A] là ánh xạ từ tên miền A đến tên miền đồng Boolean, v.v.), tôi muốn viết một hàm chung, sạch để thực hiện thao tác chuyển đổi (ví dụ: chuyển bản đồ danh sách sang vị trí được chuyển đổi danh sách bản đồ). Tuy nhiên, tôi gặp rắc rối vì ngoài toán tử(), Scala dường như không có API hợp nhất để xem các bộ sưu tập trừu tượng như ánh xạ?Transposing collection-of-collections tùy ý trong Scala

Vì vậy, tôi sẽ viết một chuyển vị riêng cho từng loại thu-of-bộ sưu tập như sau:

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

Ai đó có thể giúp tôi thống nhất các phương pháp này thành một bộ sưu tập bộ sưu tập-of-generic transpose? Nó cũng sẽ giúp tôi (và tôi chắc chắn những người khác) tìm hiểu một số tính năng hữu ích của Scala trong quá trình này.

ps: Tôi đã bỏ qua xử lý ngoại lệ và giả định bộ sưu tập bộ sưu tập đầu vào là hình chữ nhật, tức là tất cả các phần tử tên miền của bộ sưu tập bên trong cấu thành cùng một bộ.

Trả lời

8

Tôi chắc chắn rằng phiên bản lộn xộn sau đây sử dụng các loại lớp có thể được làm sạch rất nhiều, nhưng nó hoạt động như một chứng minh nhanh về khái niệm. Tôi không thấy một cách dễ dàng để có được các loại trở lại ngay mà không cần loại phương pháp phụ thuộc (tôi chắc chắn rằng nó có thể), do đó bạn sẽ phải sử dụng -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) }) 
)) 

Và bây giờ cho một số xét nghiệm:

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

Vì vậy, nó hoạt động như mong muốn.

+0

Cảm ơn - điều này rất hữu ích! Tôi mất khá nhiều thời gian để hiểu những gì bạn đã làm vì tôi không quen thuộc với một số tính năng cao cấp của Scala mà bạn đã sử dụng (đó là một lý do tuyệt vời cho tôi để tìm hiểu các tính năng này chi tiết hơn bây giờ!). – Ashwin

Các vấn đề liên quan