2010-08-07 9 views
8

Trong Scala Tôi muốn để có thể viếtScala Immutable Multimap

val petMap = ImmutableMultiMap(Alice->Cat, Bob->Dog, Alice->Hamster) 

Các cơ bản Bản đồ [Chủ đầu tư, Set [Pet]] nên có cả Bản đồ và Đặt bất biến. Đây là bản nháp đầu tiên cho ImmutibleMultiMap với đối tượng đồng hành:

import collection.{mutable,immutable} 

class ImmutableMultiMap[K,V] extends immutable.HashMap[K,immutable.Set[V]] 

object ImmutableMultiMap { 
    def apply[K,V](pairs: Tuple2[K,V]*): ImmutableMultiMap[K,V] = { 
    var m = new mutable.HashMap[K,mutable.Set[V]] with mutable.MultiMap[K,V] 
    for ((k,v) <- pairs) m.addBinding(k,v) 
    // How do I return the ImmutableMultiMap[K,V] corresponding to m here? 
    } 
} 

Bạn có thể giải quyết dòng nhận xét một cách thanh lịch không? Cả bản đồ và các bộ sẽ trở nên bất biến.

Cảm ơn!

+1

Điều này có thể hữu ích như là một ví dụ về làm thế nào để chuyển đổi một có thể thay đổi vào một bản đồ bất biến: http://stackoverflow.com/questions/2817055/ chuyển đổi-mutable-to-immutable-bản đồ –

Trả lời

3

Bạn có vấn đề lớn hơn, vì không có phương thức nào trong ImmutableMultiMap sẽ trả về ImmutableMultiMap - do đó không thể thêm thành phần vào nó và hàm tạo không hỗ trợ tạo phần tử. Vui lòng xem các triển khai hiện có và chú ý đến đối tượng đồng hành là builder và các phương pháp có liên quan.

+0

Cảm ơn Daniel. Tôi đã thử và giải mã các công cụ xây dựng, bằng cách đi qua mã nguồn cho đối tượng đồng hành để bất biến.HashSet. Tuy nhiên, tôi không thể hiểu được nó. Bạn có thể chỉ cho tôi cách bạn giải quyết vấn đề xây dựng Bản đồ ImmutableMultiMap mong muốn không? – PerfectTiling

4

Tôi đã viết lại cùng một phương thức này hai lần ngay bây giờ, tại các công việc liên tiếp. :) Ai đó thực sự Oughta làm cho nó tổng quát hơn. Nó rất tiện dụng để có một phiên bản tổng cộng.

/** 
    * Like {@link scala.collection.Traversable#groupBy} but lets you return both the key and the value for the resulting 
    * Map-of-Lists, rather than just the key. 
    * 
    * @param in the input list 
    * @param f the function that maps elements in the input list to a tuple for the output map. 
    * @tparam A the type of elements in the source list 
    * @tparam B the type of the first element of the tuple returned by the function; will be used as keys for the result 
    * @tparam C the type of the second element of the tuple returned by the function; will be used as values for the result 
    * @return a Map-of-Lists 
    */ 
    def groupBy2[A,B,C](in: List[A])(f: PartialFunction[A,(B,C)]): Map[B,List[C]] = { 

    def _groupBy2[A, B, C](in: List[A], 
          got: Map[B, List[C]], 
          f: PartialFunction[A, (B, C)]): Map[B, List[C]] = 
    in match { 
     case Nil => 
     got.map {case (k, vs) => (k, vs.reverse)} 

     case x :: xs if f.isDefinedAt(x) => 
     val (b, c) = f(x) 
     val appendTo = got.getOrElse(b, Nil) 
     _groupBy2(xs, got.updated(b, c :: appendTo), f) 

     case x :: xs => 
     _groupBy2(xs, got, f) 
    } 

    _groupBy2(in, Map.empty, f) 
    } 

Và bạn sử dụng nó như thế này:

val xs = (1 to 10).toList 
groupBy2(xs) { 
    case i => (i%2 == 0, i.toDouble) 
} 

res3: Map[Boolean,List[Double]] = Map(false -> List(1.0, 3.0, 5.0, 7.0, 9.0),  
             true -> List(2.0, 4.0, 6.0, 8.0, 10.0)) 
+0

Sử dụng câu trả lời này nhiều lần. Lưu ý rằng 'Seq' là tổng quát hơn danh sách và chỉ yêu cầu thay đổi chữ ký và chuyển đổi' c :: appendTo' thành 'c +: seq'. Tôi nghĩ rằng câu trả lời sẽ được cải thiện bằng cách nâng cấp lên 'Seq'? – simbo1905