2012-01-11 38 views
5

tôi muốn đạt được một cái gì đó như sau:Bản đồ một mục duy nhất của một bản đồ

(_ : Map[K,Int]).mapKey(k, _ + 1) 

mapKey chức năng áp dụng đối số thứ hai của nó (Int => Int) chỉ với giá trị được lưu trữ dưới k. Có điều gì đó bên trong lib chuẩn không? Nếu tôi không đặt cược có gì đó trong Scalaz.

Tất nhiên tôi có thể tự viết chức năng này (m.updated(k,f(m(k))) và đơn giản của nó để làm như vậy. Nhưng tôi đã đi qua vấn đề này nhiều lần, vì vậy có thể nó đã được thực hiện?

Đối Scalaz Tôi tưởng tượng một cái gì đó dọc theo đoạn mã sau:

(m: Map[A,B]).project(k: A).map(f: B => B): Map[A,B] 
+0

Bạn muốn điều gì xảy ra nếu phím 'a' không có trong bản đồ? Không có gì đúng? Tôi hỏi vì 'cập nhật' sẽ chèn' (a -> f (m (a)) '... – huynhjl

+0

@huynhjl Đối với trường hợp sử dụng của tôi, tôi có một bản đồ với giá trị mặc định. Không có gì xảy ra, chú ý rằng các giải pháp đơn giản của tôi sẽ thất bại với một ngoại lệ. – ziggystar

Trả lời

3

Bạn có thể tất nhiên thêm

def changeForKey[A,B](a: A, fun: B => B): Tuple2[A, B] => Tuple2[A, B] = { kv => 
    kv match { 
    case (`a`, b) => (a, fun(b)) 
    case x => x 
    } 
} 

val theMap = Map('a -> 1, 'b -> 2) 
theMap map changeForKey('a, (_: Int) + 1) 
res0: scala.collection.immutable.Map[Symbol,Int] = Map('a -> 2, 'b -> 2) 

Nhưng điều này sẽ phá vỡ bất kỳ tối ưu hóa liên quan đến bộ nhớ tái sử dụng và truy cập.

Tôi cũng đã đưa ra một giải pháp scalaz khá dài dòng và không hiệu quả bằng cách sử dụng dây kéo cho đề xuất project phương pháp của bạn:

theMap.toStream.toZipper.flatMap(_.findZ(_._1 == 'a).flatMap(elem => elem.delete.map(_.insert((elem.focus._1, fun(elem.focus._2)))))).map(_.toStream.toMap) 

hoặc

(for { 
    z <- theMap.toStream.toZipper 
    elem <- z.findZ(_._1 == 'a) 
    z2 <- elem.delete 
} yield z2.insert((elem.focus._1, fun(elem.focus._2)))).map(_.toStream.toMap) 

Có lẽ ít được sử dụng. Tôi chỉ đăng để tham khảo.

1

Bạn có thể dắt nó với điều này để nó tạo ra một bản đồ mới dựa trên cái cũ một:

class MapUtils[A, B](map: Map[A, B]) { 
    def mapValueAt(a: A)(f: (B) => B) = map.get(a) match { 
    case Some(b) => map + (a -> f(b)) 
    case None => map 
    } 
} 

implicit def toMapUtils[A, B](map: Map[A, B]) = new MapUtils(map) 

val m = Map(1 -> 1) 
m.mapValueAt(1)(_ + 1) 
// Map(1 -> 2) 
m.mapValueAt(2)(_ + 1) 
// Map(1 -> 1) 
3

Dưới đây là một cách:

scala> val m = Map(2 -> 3, 5 -> 11) 
m: scala.collection.immutable.Map[Int,Int] = Map(2 -> 3, 5 -> 11) 

scala> m ++ (2, m.get(2).map(1 +)).sequence 
res53: scala.collection.immutable.Map[Int,Int] = Map(2 -> 4, 5 -> 11) 

scala> m ++ (9, m.get(9).map(1 +)).sequence 
res54: scala.collection.immutable.Map[Int,Int] = Map(2 -> 3, 5 -> 11) 

này hoạt động vì (A, Option[B]).sequence cho Option[(A, B)]. (sequence nói chung, hãy nhập các loại trong ra ngoài, ví dụ: F[G[A]] => [G[F[A]], được cho F : TraverseG : Applicative.)

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