【问题标题】:Scala enhanced collectionsScala 增强的集合
【发布时间】:2014-01-04 21:01:56
【问题描述】:

我感兴趣的是 Scala 是否提供了操作异构集合的便捷方式?

尤其是变体类型和多键多映射。

我知道第一个可以构建在嵌套的 Either 类 Either[Either[A, B], C] 之上,第二个可以构建在嵌套的 Map 类 Map[A, Map[B, Set[C]]] 之上,但是直接执行更新/删除操作似乎太复杂了每次我需要它们(而且我经常需要它们)。

所以我正在寻找一个现成的解决方案。或者也许标准库中有一种方便简单的方法?无论如何,如果你能建议第三方框架,也可以。

【问题讨论】:

  • 异构集合通常是代码异味的标志——如果你需要在同一个集合中保留不同的类型,那么它们可能应该有一些共同的接口——即这应该通过多态来实现。地图的地图称为表格 - Guava provides an API for this。我不知道 Scala 有类似的 API。
  • @Boris the Spider,不熟悉的请不要回答。问题显然是关于 Scala,而不是 Java。还将变体类型(这是在许多语言中实现多态性的一种众所周知的方式)视为“代码气味”似乎很有争议。
  • 我没有回答,我评论了。
  • @BoristheSpider 异构集合的良好用途包括基于索引参数化列表元素、基于键参数化地图元素或泛化方法签名。不过,我同意它可以是一种钝器。

标签: scala collections


【解决方案1】:

Scala 不提供使异构集合易于管理的工具。

而不是使用复杂的Either 嵌套,在其中你选择一个可能毫无意义的特定树结构,你应该使用shapeless'HLists。我不确定你会认为这很容易,但它肯定比Either-trees 更紧凑(一旦你学会了足够多的无形魔法)。

我熟悉的任何通用库都不支持多键映射。这种映射有很多可能的选择:键是分层的还是冗余的?对称查找是否重要(即,如果您有一个 A 密钥,您可以获得映射 B => C,如果您有一个 B 密钥,则可以获得 A => C)?我只想指出,编写一个使您能够在您喜欢的任何形式的多键映射上定义自己的方法的包装器并不难。您可能必须编写自己的包装器才能获得所需的行为。最简单的就是提供 2-ary contains 和 get 和 update 方法:

implicit class NestedMapAs2Map[A, B, C](val m: Map[A, Map[B, C]]) extends AnyVal {
  def contains2(a: A, b: B): Boolean = m.get(a).exists(_ contains b)
  def get2(a: A, b: B): Option[C] = m.get(a).flatMap(_.get(b))
  def updated2(a: A, b: B, c: C) = m.updated(a, m.get(a).map(mi => mi.updated(b,c)).getOrElse(Map(b -> c)))
}

【讨论】:

  • 感谢您推荐无形。我去看看。关于多键地图。通常我使用分层键,并且查找是右关联不对称的。就像我在上面的例子中介绍的那样。这就是为什么我不确定@RobinGreen 建议使用元组的效率。
  • @Eliah - 如果您想要A => B => C 形式的东西,那么拥有(A,B) => C 的地图既不高效也不方便。所以,不,元组可能不是你想要的,除非你总是手头有两个键。
【解决方案2】:

要创建“变体类型”,您可以使用继承。要“保证”只存在 N 个变体(好吧,无论如何,从 Scala 代码来看,Java 代码不会被阻止创建更多子类),您可以使用 sealed trait。如果您需要使用已经存在且无法修改(和/或移动)到您的 trait 的 extend 类型,您可以将其包装在带有单个字段的 case class 中。

我认为您应该能够使用值类(如果MyTrait 是一个通用特征,则使用extends AnyVal with MyTrait)来防止这种情况下的运行时开销,但我还没有尝试过。

对于多键多图,您可以使用Map[(A,B), Set[C]]。 Scala 中的元组可以从 2 个值到 22 个值。或者,还有一个 MultiMap 特征,您可以将其混合到可变映射中。

【讨论】:

  • 感谢您的回答,罗宾!与嵌套 Maps 方法相比,带有元组键的 Map 在查找方面是否具有相同的性能?我试图放入的数据具有分层性质。
  • 这取决于您选择的数据和Map 实现,我想。我建议你以两种方式对其进行基准测试。
  • 您如何获得特定AMap[B, Set[C]]
  • 啊,为此您必须执行类似.filter(_._1 == a) 整体Map[(A, B), Set[C]] 的操作。这不会特别有效(并且生成的 Map 也不会有正确的类型!)
猜你喜欢
  • 2013-02-27
  • 2021-11-09
  • 1970-01-01
  • 2015-11-30
  • 2015-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多