Зіставити як ключі, так і значення карти Scala


89

Риса Скали MapLikeмає метод

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

Але я часом хочу інший тип:

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

Чи є простий спосіб зробити це, чого мені не вистачає? Звичайно, це можна зробити за допомогою складки.

Відповіді:


166

mapметод переглядає всі (key, value)пари. Ви можете використовувати його так:

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

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

8
Якщо у вас вже є функція f : (A,B) => (A,C), тоді ви можете просто m.map(f.tupled). Працює з, val f = (x: String, y: Int) => (x, y+1)але дивним чином repl скаржиться, якщо я визначу fеквівалентно з def.
Dan Burton

2
чого caseтут досягає ключове слово ?
Вездесущий

@Omnipresent {case (key, value) => ...}- у цьому випадку просто узгодження шаблонів. Замість того, щоб надати функцію a map, я надаю їй часткову функцію.
тенші

Примітка: caseдозволить вам розміщувати типи в його шаблоні, але це не є безпечним, оскільки може спричинити помилку виконання (оскільки це просто збіг шаблону). Тим часом, якщо ви коли-небудь зміните структуру колекції під mapфункцією, так що буде занадто мало або занадто багато об'єктів для інтерпретації (key, value), тоді ще раз, я сподіваюся, ви отримаєте помилку виконання. :(
комбінатор

8

Що з цим кодом:

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

Яка виробляє:

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

Це можна упакувати в корисний метод:

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

Використання:

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

Хіба це не те саме, що MapLike#transform?
Хосам Алі


2

З деякими 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)

Мені більше подобається рішення @ tenshi.


0

Ви можете створити клас корисності:

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)

Код не перевірено, але він повинен працювати якось подібним чином.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.