Scala中有双向映射这样的东西吗?

Iva*_*van 22 collections scala map bidirectional-relation scala-collections

我想链接2列唯一标识符,并能够通过第二列值获得第一列值,并通过第一列值获得第二列值.就像是

Map(1 <-> "one", 2 <-> "two", 3 <-> "three")
Run Code Online (Sandbox Code Playgroud)

Scala有这样的设施吗?

实际上我还需要更多:3列在三元组中选择三元组中的任何一条(在整个地图中永远不会遇到单个值).但是2列双向映射也可以提供帮助.

Pet*_*itz 10

我的BiMap方法:

object BiMap {
  private[BiMap] trait MethodDistinctor
  implicit object MethodDistinctor extends MethodDistinctor
}

case class BiMap[X, Y](map: Map[X, Y]) {
  def this(tuples: (X,Y)*) = this(tuples.toMap)
  private val reverseMap = map map (_.swap)
  require(map.size == reverseMap.size, "no 1 to 1 relation")
  def apply(x: X): Y = map(x)
  def apply(y: Y)(implicit d: BiMap.MethodDistinctor): X = reverseMap(y)
  val domain = map.keys
  val codomain = reverseMap.keys
}

val biMap = new BiMap(1 -> "A", 2 -> "B")
println(biMap(1)) // A
println(biMap("B")) // 2
Run Code Online (Sandbox Code Playgroud)

当然可以添加语法<->而不是->.

  • @andypetrella但是这意味着每次调用`apply(y:Y)`时都会交换原始映射,所以你在`codomain`上遇到运行时问题! (2认同)
  • 使用双倍内存来实现双映射功能对我来说似乎是一个公平的权衡. (2认同)
  • 这似乎很像番石榴的“ BiHashMap”,因为它有两个地图并且它们是不可变的。但是您似乎正在使用该类型来消除番石榴`.reverse```方法。这不是使String &lt;-&gt; String成为不可能吗?在这种情况下,您需要添加`.reverse`?吗?那不会消除```methodDistinctor```吗?哪一个可以给您确切的BiHashMap,对吗? (2认同)

小智 10

番石榴有一个你可以随之使用的bimap

import scala.collection.JavaConversions._
Run Code Online (Sandbox Code Playgroud)


and*_*lla 1

我不认为它是开箱即用的,因为通用行为不容易提取

如何在干净的 api 中处理与多个键匹配的值?

然而,对于特定情况,这里有一个很好的练习,可能会有所帮助。它必须更新,因为没有使用哈希并且获取键或值的时间复杂度为 O(n)。

但我们的想法是让你写一些与你提议的类似的东西,但使用 Seq 而不是 Map...

在implicit和trait的帮助下,再加上find,你可以用一种干净的api(fromKeyfromValue)来模拟你需要的东西。

特殊之处在于,一个值不应该出现在多个地方......至少在这个实现中。

  trait BiMapEntry[K, V] {
    def key:K
    def value:V
  }

  trait Sem[K] {

    def k:K

    def <->[V](v:V):BiMapEntry[K, V] = new BiMapEntry[K,  V]() { val key = k; val value = v}
  }

  trait BiMap[K, V] {

    def fromKey(k:K):Option[V]

    def fromValue(v:V):Option[K]
  }


  object BiMap {
    implicit def fromInt(i:Int):Sem[Int] = new Sem[Int] {
      def k = i
    }

    implicit def fromSeq[K, V](s:Seq[BiMapEntry[K, V]]) = new BiMap[K, V] {
      def fromKey(k:K):Option[V] = s.find(_.key == k).map(_.value)
      def fromValue(v:V):Option[K] = s.find(_.value == v).map(_.key)
    }

  }




  object test extends App {

    import BiMap._



    val a = 1 <-> "a"

    val s = Seq(1 <-> "a", 2 <-> "b")

    println(s.fromKey(2))
    println(s.fromValue("a"))

  }
Run Code Online (Sandbox Code Playgroud)