我可以 return 使用 for-yield 语法在 Scala 中映射集合吗?
Can I return Map collection in Scala using for-yield syntax?
我是 Scala 的新手,所以希望你能容忍这个问题,以防你觉得它很菜:)
我写了一个函数,return使用 yield 语法将元素序列化为:
def calculateSomeMetrics(names: Seq[String]): Seq[Long] = {
for (name <- names) yield {
// some auxiliary actions
val metrics = somehowCalculateMetrics()
metrics
}
}
现在我需要将其修改为 return 一个映射以针对每个计算值保留原始名称:
def calculateSomeMetrics(names: Seq[String]): Map[String, Long] = { ... }
我尝试使用相同的 yield 语法,但生成的是元组而不是单个元素:
def calculateSomeMetrics(names: Seq[String]): Map[String, Long] = {
for (name <- names) yield {
// Everything is the same as before
(name, metrics)
}
}
但是,编译器会根据编译器错误消息
解释它 Seq[(String, Long)]
type mismatch;
found : Seq[(String, Long)]
required: Map[String, Long]
所以我想知道,实现这样的事情的 "canonical Scala way" 是什么?
或者:
def calculateSomeMetrics(names: Seq[String]): Map[String, Long] = {
(for (name <- names) yield {
// Everything is the same as before
(name, metrics)
}).toMap
}
或者:
names.map { name =>
// doStuff
(name, metrics)
}.toMap
创建不同集合类型的有效方法是使用 scala.collection.breakOut
。它适用于 Map
s 并且也适用于理解:
import scala.collection.breakOut
val x: Map[String, Int] = (for (i <- 1 to 10) yield i.toString -> i)(breakOut)
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)
}
与 toMap
解决方案的比较:在 toMap
之前创建了 Tuple2
的中间 Seq
(在某些情况下,顺便说一下,它也可能是 Map
) 并由此创建 Map
,而 breakOut
省略了中间 Seq
创建并直接创建 Map
而不是中间 Seq
.
通常这在内存或 CPU 使用(+ GC 压力)方面没有太大差异,但有时这些事情很重要。
这里有几个链接是其他人指向我的,或者我后来设法找到的,只是将它们组合成一个答案以供我将来参考。
breakOut
- Michał in 建议
toMap
- 在 this thread
- 关于
breakOut
工作原理的深刻解释 - 在 this answer 中
- 不过请注意,
breakOut
is going away, as noted by Karl
我是 Scala 的新手,所以希望你能容忍这个问题,以防你觉得它很菜:)
我写了一个函数,return使用 yield 语法将元素序列化为:
def calculateSomeMetrics(names: Seq[String]): Seq[Long] = {
for (name <- names) yield {
// some auxiliary actions
val metrics = somehowCalculateMetrics()
metrics
}
}
现在我需要将其修改为 return 一个映射以针对每个计算值保留原始名称:
def calculateSomeMetrics(names: Seq[String]): Map[String, Long] = { ... }
我尝试使用相同的 yield 语法,但生成的是元组而不是单个元素:
def calculateSomeMetrics(names: Seq[String]): Map[String, Long] = {
for (name <- names) yield {
// Everything is the same as before
(name, metrics)
}
}
但是,编译器会根据编译器错误消息
解释它Seq[(String, Long)]
type mismatch;
found : Seq[(String, Long)]
required: Map[String, Long]
所以我想知道,实现这样的事情的 "canonical Scala way" 是什么?
或者:
def calculateSomeMetrics(names: Seq[String]): Map[String, Long] = {
(for (name <- names) yield {
// Everything is the same as before
(name, metrics)
}).toMap
}
或者:
names.map { name =>
// doStuff
(name, metrics)
}.toMap
创建不同集合类型的有效方法是使用 scala.collection.breakOut
。它适用于 Map
s 并且也适用于理解:
import scala.collection.breakOut
val x: Map[String, Int] = (for (i <- 1 to 10) yield i.toString -> i)(breakOut)
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)
}
与 toMap
解决方案的比较:在 toMap
之前创建了 Tuple2
的中间 Seq
(在某些情况下,顺便说一下,它也可能是 Map
) 并由此创建 Map
,而 breakOut
省略了中间 Seq
创建并直接创建 Map
而不是中间 Seq
.
通常这在内存或 CPU 使用(+ GC 压力)方面没有太大差异,但有时这些事情很重要。
这里有几个链接是其他人指向我的,或者我后来设法找到的,只是将它们组合成一个答案以供我将来参考。
breakOut
- Michał in 建议
toMap
- 在 this thread- 关于
breakOut
工作原理的深刻解释 - 在 this answer 中- 不过请注意,
breakOut
is going away, as noted by Karl
- 不过请注意,