Scala: Как создать карту [K, V] из набора [K] и функцию от K до V? - PullRequest
14 голосов
/ 07 апреля 2011

Каков наилучший способ создания Map[K,V] из Set[K] и функции от K до V?

Например, предположим, у меня есть

scala> val s = Set(2, 3, 5)
s: scala.collection.immutable.Set[Int] = Set(2, 3, 5)

и

scala> def func(i: Int) = "" + i + i
func: (i: Int)java.lang.String

Какой самый простой способ создания Map[Int, String](2 -> "22", 3 -> "33", 5 -> "55")

Ответы [ 7 ]

20 голосов
/ 07 апреля 2011

Вы можете использовать foldLeft:

val func2 = (r: Map[Int,String], i: Int) => r + (i -> func(i))
s.foldLeft(Map.empty[Int,String])(func2)

Это будет работать лучше, чем решение Джеспера, потому что foldLeft создает Map за один проход.Код Джеспера сначала создает промежуточную структуру данных, которую затем необходимо преобразовать в окончательное Map.

Обновление: Я написал микро-тест , проверяющий скоростькаждого из ответов:

Jesper (original): 35s 738ms
Jesper (improved): 11s 618ms
           dbyrne: 11s 906ms
         Rex Kerr: 12s 206ms
          Eastsun: 11s 988ms

Похоже, все они в значительной степени одинаковы, если вы избегаете построения промежуточной структуры данных.

16 голосов
/ 07 апреля 2011

Что по этому поводу:

(s map { i => i -> func(i) }).toMap

Это сопоставляет элементы s с кортежами (i, func(i)), а затем преобразует полученную коллекцию в Map.

Примечание: i -> func(i) совпадает с (i, func(i)).

dbyrne предлагает сначала создать представление набора (см. Его ответ и комментарии), что предотвращает создание промежуточной коллекции, улучшая производительность:

(s.view map { i => i -> func(i) }).toMap
7 голосов
/ 07 апреля 2011
scala> import collection.breakOut
import collection.breakOut

scala> val set = Set(2,3,5)
set: scala.collection.immutable.Set[Int] = Set(2, 3, 5)

scala> def func(i: Int) = ""+i+i
func: (i: Int)java.lang.String

scala> val map: Map[Int,String] = set.map(i => i -> func(i))(breakOut)
map: Map[Int,String] = Map(2 -> 22, 3 -> 33, 5 -> 55)

scala>
6 голосов
/ 07 апреля 2011

В дополнение к существующим ответам

Map() ++ set.view.map(i => i -> f(i))

довольно короткий и работает так же быстро, как и ответы (fold / breakOut).

(Обратите внимание на представление, чтобы предотвратить создание новой коллекции; она выполняет переназначение по ходу дела.)

1 голос
/ 08 апреля 2011

Другим решениям не хватает творчества. Вот моя собственная версия, хотя мне бы очень хотелось избавиться от карты _.head.

s groupBy identity mapValues (_.head) mapValues func
1 голос
/ 07 апреля 2011

Как и во всех замечательных языках, есть миллион способов сделать все.

Вот стратегия, которая объединяет наборы с самим собой.

val s = Set(1,2,3,4,5)
Map(s.zip(s.map(_.toString)).toArray : _*)

РЕДАКТИРОВАТЬ: (_.toString) можетбыть заменено некоторой функцией, которая возвращает что-то типа V

0 голосов
/ 08 апреля 2011

Без определения функции (i: Int) с использованием оператора «повторение строки» *:

scala> s map { x => x -> x.toString*2 } toMap
res2: scala.collection.immutable.Map[Int,String] = Map(2 -> 22, 3 -> 33, 5 -> 55)
...