【问题标题】:Convert a mutable Map of Seq to an immutable Map of IndexedSeq in Scala在 Scala 中将 Seq 的可变 Map 转换为 IndexedSeq 的不可变 Map
【发布时间】:2012-03-13 11:51:01
【问题描述】:

我需要处理代表人们的大量记录(数百万)。我想根据出生年份创建一个分区,然后分别处理每个组。我正在尝试创建一个功能解决方案(无/最少的可变数据),以便它是线程安全的并且可以并行化。

在我的第一次尝试中,我创建了一个尾递归函数,它构建了一个 Map[Int, IndexedSeq],将每个出生年份映射到一系列人员记录。我需要一个索引序列,因为我将对每个组中的人进行随机访问。这是我的代码:

@tailrec
def loop(people: Seq[Person],
         map: Map[Int, IndexedSeq[Person]] = Map()): Map[Int, IndexedSeq[Person]] = {
  if (people.isEmpty) map
  else {
    val person = people.head
    val yearOfBirth = person.yearOfBirth
    val seq = map.getOrElse(yearOfBirth, IndexedSeq())
    loop(people.tail, map + (yearOfBirth -> (seq :+ person)))
  }
}

这可行,但效率不高。通过允许少量非常局部的可变性,我可以做得更好。如果所有可变变量都在堆栈上,那么代码仍然是线程安全的,只要输出 Map 是不可变的。

我想通过在内部构建一个可变的Map[Int, List[Person]] 来实现这一点,然后将其有效地转换为一个不可变的Map[Int, IndexedSeq[Person]] 作为返回值。

如何以最有效的方式将可变的MapList 项目转换为不可变的Map[Int, IndexedSeq[Person]]?请注意,每个出生年份组中的人没有特定的顺序。

【问题讨论】:

  • 一个小问题,可能无关紧要:因为你在出生年份进行分区,AFAICT 你永远不会在这个线程之外传递地图本身。

标签: scala map immutability


【解决方案1】:

为什么不使用Seq 特征的groupBy 函数? (文档在这里:http://www.scala-lang.org/api/current/index.html#scala.collection.Seq

def groupByYearOfBirth(people: Seq[Person]) = people.groupBy(_.yearofBirth)

编辑:与我最初的提议相反,不要使用.mapValues(_.toIndexedSeq)to provide anIndexedSeq`。 Daniel 在下面的评论中解释了原因。

【讨论】:

  • 我没有使用你的技术,因为我不知道。 :-) 看起来它会完全满足我的需要。 Scala 不是很棒吗?!谢谢。
  • 是的,在 scala 中总是一样的:首先仔细查看 API,大多数时候,它包含您需要的内容。 ;)
  • 不要那样使用mapValuesmapValues 的实现就像一个视图,这意味着它会在您每次访问该值时应用该转换。鉴于SeqIndexedSeq 之间的区别,这样做很可能不会为您带来任何好处。改用普通的map,创建一个新的Map
  • 非常感谢丹尼尔,我不知道它会在每次访问时评估新值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-12-15
  • 2020-07-16
  • 1970-01-01
  • 2018-03-31
  • 2018-02-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多