我可以使用for-yield语法在Scala中返回Map集合吗?

Vas*_*kin 2 dictionary scala yield seq

我是Scala的新手,所以希望你能在这个问题中容忍这个问题,如果你发现它是noobish :)

我写了一个函数,它使用yield语法返回一个Seq元素:

def calculateSomeMetrics(names: Seq[String]): Seq[Long] = {
  for (name <- names) yield {
    // some auxiliary actions
    val metrics = somehowCalculateMetrics()
    metrics
  }
}
Run Code Online (Sandbox Code Playgroud)

现在我需要修改它以返回Map以保留原始名称对每个计算值:

def calculateSomeMetrics(names: Seq[String]): Map[String, Long] = { ... }
Run Code Online (Sandbox Code Playgroud)

我试图使用相同的yield语法,但产生一个元组而不是单个元素:

def calculateSomeMetrics(names: Seq[String]): Map[String, Long] = {
  for (name <- names) yield {
    // Everything is the same as before
    (name, metrics)
  }
}
Run Code Online (Sandbox Code Playgroud)

但是,编译器会Seq[(String, Long)]根据编译器错误消息对其进行解释

type mismatch;
  found   : Seq[(String, Long)]
  required: Map[String, Long]
Run Code Online (Sandbox Code Playgroud)

所以我想知道,实现这样的事情的"规范Scala方式"是什么?

Gáb*_*kos 8

创建不同集合类型的有效方法是使用scala.collection.breakOut.它既适用于Maps,也适用于理解:

import scala.collection.breakOut

val x: Map[String, Int] = (for (i <- 1 to 10) yield i.toString -> i)(breakOut)
Run Code Online (Sandbox Code Playgroud)

x:Map [String,Int] = Map(8 - > 8,4 - > 4,9 - > 9,5 - > 5,10 - > 10,6 - > 6,1 - > 1,2 - > 2 ,7 - > 7,3 - > 3)

在你的情况下它也应该工作:

import scala.collection.breakOut

def calculateSomeMetrics(names: Seq[String]): Map[String, Long] = {
  (for (name <- names) yield {
    // Everything is the same as before
    (name, metrics)
  })(breakOut)
}
Run Code Online (Sandbox Code Playgroud)

比较与toMap解决方案:之前toMap创建一个中间SeqTuple2S(这亦可能是Map在某些情况下也是如此),并从它创建的Map,而breakOut省略了这中间Seq的创建和创建Map的,而不是直接在中间Seq.

通常这不是内存或CPU使用量(+ GC压力)的巨大差异,但有时这些事情很重要.

  • 我会偏离使用`breakOut`直到这个特定代码成为瓶颈.阅读和理解是违反直觉的. (2认同)
  • 请注意,新系列设计中的[突破即将消失](http://www.scala-lang.org/blog/2017/05/30/tribulations-canbuildfrom.html#breakout-escape-hatch). (2认同)

Yuv*_*kov 5

或者:

def calculateSomeMetrics(names: Seq[String]): Map[String, Long] = {
  (for (name <- names) yield {
    // Everything is the same as before
    (name, metrics)
  }).toMap
}
Run Code Online (Sandbox Code Playgroud)

要么:

names.map { name =>
  // doStuff
  (name, metrics)
}.toMap
Run Code Online (Sandbox Code Playgroud)