【问题标题】:Scala: How to create a Map[K,V] from a Set[K] and a function from K to V?Scala:如何从 Set[K] 创建 Map[K,V] 和从 K 到 V 的函数?
【发布时间】:2011-07-31 18:30:04
【问题描述】:

Set[K] 创建Map[K,V] 并从KV 的最佳方法是什么?

例如,假设我有

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")的最简单方法是什么

【问题讨论】:

标签: scala functional-programming scala-collections


【解决方案1】:

你可以使用foldLeft:

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

这将比 Jesper 的解决方案执行得更好,因为 foldLeft 一次性构造了 Map。 Jesper 的代码首先创建了一个中间数据结构,然后需要将其转换为最终的Map

更新:我写了一个micro benchmark测试每个答案的速度:

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

只要您避免构建中间数据结构,它们看起来都几乎相同。

【讨论】:

  • 如果我在我的解决方案中的 .toMap 之前添加一个 .view 怎么办 - 这会阻止构建中间集合吗?
  • @Jesper:您需要在map 之前添加.view,就像这样 - (s.view.map { i => i -> func(i) }).toMap
  • @Jesper:更新了我的答案。显示添加 .view 带来的显着改进。
【解决方案2】:

这个呢:

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

这会将s 的元素映射到元组(i, func(i)),然后将生成的集合转换为Map

注意:i -> func(i)(i, func(i)) 相同。

dbyrne 建议首先创建集合的视图(参见他的答案和 cmets),这可以防止生成中间集合,从而提高性能:

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

【讨论】:

  • 我想知道,有没有办法将 func 显式提供给 toMap(即指定隐式参数)。
  • @subsub 如果您将func 更改为:def func(i: Int) = i -> ("" + i + i),那么您可以这样做:(s.view map func).toMap。所以,你会让func 返回元组。
【解决方案3】:
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>

【讨论】:

【解决方案4】:

除了现有的答案,

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

很短,性能和更快的答案一样好(fold/breakOut)。

(注意视图以防止创建新集合;它会在执行过程中进行重新映射。)

【讨论】:

  • @Luigi Plinge - 如果您使用返回 () 的函数,所有内容都会映射到 ()
【解决方案5】:

其他解决方案缺乏创造力。这是我自己的版本,虽然我真的很想摆脱 _.head 地图。

s groupBy identity mapValues (_.head) mapValues func

【讨论】:

    【解决方案6】:

    与所有伟大的语言一样,每件事都有一百万种方法。

    这是一个自行压缩系列的策略。

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

    编辑:(_.toString) 可以替换为一些返回 V 类型的函数

    【讨论】:

    • 聪明,但速度慢。这三种快速解决方案的速度比这一种快 4 倍。
    【解决方案7】:

    没有使用“字符串重复”运算符定义func(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)
    

    【讨论】:

      猜你喜欢
      • 2011-03-06
      • 2011-04-21
      • 1970-01-01
      • 1970-01-01
      • 2019-10-10
      • 2013-04-13
      • 1970-01-01
      • 2020-04-08
      • 2018-11-23
      相关资源
      最近更新 更多