Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there such a thing as bidirectional maps in Scala?

I'd like to link 2 columns of unique identifiers and be able to get a first column value by a second column value as well as a second column value by a first column value. Something like

Map(1 <-> "one", 2 <-> "two", 3 <-> "three")

Is there such a facility in Scala?

Actually I need even more: 3 columns to select any in a triplet by another in a triplet (individual values will never be met more than once in the entire map). But a 2-column bidirectional map can help too.

like image 411
Ivan Avatar asked Mar 24 '12 09:03

Ivan


People also ask

What is the map type in the scala?

There are two kinds of Maps, the immutable and the mutable. The difference between mutable and immutable objects is that when an object is immutable, the object itself can't be changed. By default, Scala uses the immutable Map.

Is scala map a HashMap?

Scala HashMap is used to store objects and it take the object in the form of key value pair. For every value there should be one key associated with it. Scala collection contains this Hashmap and it is the implementation of MAP.

What does map return in scala?

Delta Lake with Apache Spark using Scala map() method is a member of TraversableLike trait, it is used to run a predicate method on each elements of a collection. It returns a new collection.


4 Answers

Guava has a bimap that you can use along with

import scala.collection.JavaConversions._
like image 129
Steve Avatar answered Oct 10 '22 07:10

Steve


My BiMap approach:

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

Of course one can add syntax for <-> instead of ->.

like image 27
Peter Schmitz Avatar answered Oct 10 '22 05:10

Peter Schmitz


Here's a quick Scala wrapper for Guava's BiMap.

import com.google.common.{collect => guava}
import scala.collection.JavaConversions._
import scala.collection.mutable
import scala.languageFeature.implicitConversions

class MutableBiMap[A, B] private (
    private val g: guava.BiMap[A, B] = new guava.HashBiMap[A, B]()) {

  def inverse: MutableBiMap[B, A] = new MutableBiMap[B, A](g.inverse)
}

object MutableBiMap {

  def empty[A, B]: MutableBiMap[A, B] = new MutableBiMap()

  implicit def toMap[A, B] (x: MutableBiMap[A, B]): mutable.Map[A,B] = x.g
}
like image 3
Chris Martin Avatar answered Oct 10 '22 07:10

Chris Martin


I have a really simple BiMap in Scala:

  case class BiMap[A, B](elems: (A, B)*) {

    def groupBy[X, Y](pairs: Seq[(X, Y)]) = pairs groupBy {_._1} mapValues {_ map {_._2} toSet}

    val (left, right) = (groupBy(elems), groupBy(elems map {_.swap}))

    def apply(key: A) = left(key)
    def apply[C: ClassTag](key: B) = right(key)
  }

Usage:

  val biMap = BiMap(1 -> "x", 2 -> "y", 3 -> "x", 1 -> "y")
  assert(biMap(1) == Set("x", "y"))
  assert(biMap("x") == Set(1, 3))
like image 2
pathikrit Avatar answered Oct 10 '22 07:10

pathikrit