Ánh xạ cả khóa và giá trị của Bản đồ Scala


88

MapLikeĐặc điểm của Scala có phương pháp

mapValues [C] (f: (B) ⇒ C): Map[A, C] 

Nhưng đôi khi tôi muốn một kiểu khác:

mapKeysAndValues [C] (f: (A, B) ⇒ C): Map[A, C] 

Có cách nào đơn giản để làm điều này mà tôi đang thiếu không? Tất nhiên, điều này có thể được thực hiện với một nếp gấp.

Câu trả lời:


163

mapphương thức lặp lại mặc dù tất cả các (key, value)cặp. Bạn có thể sử dụng nó như thế này:

val m = Map("a" -> 1, "b" -> 2)

val incM = m map {case (key, value) => (key, value + 1)}

8
Nếu bạn đã có một chức năng f : (A,B) => (A,C), thì bạn có thể đơn giản m.map(f.tupled). Hoạt động với val f = (x: String, y: Int) => (x, y+1)nhưng kỳ lạ là repl phàn nàn nếu tôi định nghĩa ftương đương với def.
Dan Burton

2
từ khóa caseđạt được điều gì ở đây?
Toàn bộ

@Omnipresent {case (key, value) => ...}chỉ là một đối sánh mẫu trong trường hợp này. Thay vì cung cấp một hàm cho a map, tôi cung cấp cho nó một hàm một phần.
tenshi

Lưu ý: casesẽ cho phép bạn đặt các loại vào mẫu của nó, nhưng điều này không an toàn vì nó có thể tạo ra lỗi thời gian chạy (vì nó chỉ là một mẫu khớp). Trong khi đó, nếu bạn từng thay đổi cấu trúc của bộ sưu tập bên dưới maphàm để có quá ít hoặc quá nhiều đối tượng để diễn giải (key, value), thì một lần nữa, tôi hy vọng bạn sẽ gặp lỗi thời gian chạy. :(
tổ hợp

8

Điều gì về mã này:

val m = Map(1 -> "one", 2 -> "two")
def f(k: Int, v: String) = k + "-" + v
m map {case (k, v) => (k, f(k, v))}

Sản xuất:

 Map(1 -> 1-one, 2 -> 2-two)

Điều này có thể được đóng gói thành phương thức tiện ích:

def mapKeysAndValues[A,B,C](input: Map[A,B], fun: (A, B) => C) = 
  input map {case(k,v) => (k, fun(k, v))}

Sử dụng:

mapKeysAndValues(
  Map(1 -> "one", 2 -> "two"), 
  (k: Int, v: String) => k + "-" + v
)

Điều này không giống như MapLike#transform?
Hosam Aly


2

Với một số Scalaz:

scala> def fst[A, B] = (x: (A, B)) => x._1
fst: [A, B]=> (A, B) => A

scala> Map(1 -> "Lorem", 2 -> "Ipsum").map(fst &&& Function.tupled(_.toString + _))
res1: scala.collection.immutable.Map[Int,java.lang.String] = Map(1 -> 1Lorem, 2 -> 2Ipsum)

Tôi thích giải pháp của @ tenshi hơn.


0

Bạn có thể tạo một lớp tiện ích:

class MyMapLike[K,V](m:MapLike[K,V,_]){
 def mapKeysAndValues[R](f: (K, V) => R)={
   m.map{case (k,v)=> f(k,v)}
 } 
}
object MyMapLike{
 implicit def maplike2mymaplike[K,V](ml:MapLike[K,V,_]):MyMapLike[K,V]=new MyMapLike(m)

}

import MyMapLike._
Map(1 -> "one", 2 -> "two").mapKeysAndValues(k,v=>v*k)

Mã không được kiểm tra nhưng nó sẽ hoạt động bằng cách nào đó tương tự như vậy.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.