Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does there exist in Scala, or a library, an equivalent to Clojure's diff as applied to maps?

In Clojure the diff function can be applied to maps, that doesn't seem to be the case in Scala, is anyone aware of something in Scala that would make it more accessible to obtain what the Clojure diff function obtains when it is applied to maps?

Here's the Clojure diff function explained for reference.

http://clojuredocs.org/clojure_core/clojure.data/diff

like image 745
RatavaWen Avatar asked May 09 '14 17:05

RatavaWen


2 Answers

This is equivalent to Clojure's diff:

import collection.generic.CanBuildFrom

def diff[T, Col](x: Col with TraversableOnce[T], y: Col with TraversableOnce[T])
        (implicit cbf: CanBuildFrom[Col, T, Col]): (Col, Col, Col) = {
  val xs = x.toSet
  val ys = y.toSet
  def convert(s: Set[T]) = (cbf(x) ++= s).result
  (convert(xs diff ys), convert(ys diff xs), convert(xs intersect ys))
}

It can operate on any kind of TraversableOnce and will return results with the same type as its parameters:

scala> diff(Map(1 -> 2), Map(1 -> 2))
res35: (scala.collection.immutable.Map[Int,Int], scala.collection.immutable.Map[Int,Int], scala.collection.immutable.Map[Int,Int]) = (Map(),Map(),Map(1 -> 2))
like image 66
wingedsubmariner Avatar answered Nov 15 '22 05:11

wingedsubmariner


As others have said there isn't something exactly like that, but you can build it anyways. Here's my attempt that is added on as a companion to the map class. It produces the same result as the clojure diff example.

object MapsDemo extends App{
  implicit class MapCompanionOps[A,B](val a: Map[A,B]) extends AnyVal {
    def diff(b: Map[A,B]): (Map[A,B],Map[A,B],Map[A,B]) = {
          (a.filter(p => !b.exists(_ == p)),  //things-only-in-a
           b.filter(p => !a.exists(_ == p)),    //things-only-in-b
           a.flatMap(p => b.find(_ == p) ))    //things-in-both
        }
  }

    val uno = Map("same" ->"same","different" -> "one")
    val dos = Map("same" ->"same","different" -> "two","onlyhere"->"whatever")
    println(uno diff dos) //(Map(different -> one),Map(different -> two, onlyhere -> whatever),Map(same -> same))
    println( Map("a"->1).diff(Map("a"->1,"b"->2)) ) //(Map(),Map(b -> 2),Map(a -> 1))
}
like image 35
Gangstead Avatar answered Nov 15 '22 04:11

Gangstead