2014-05-09 8 views
5

In Clojure la funzione diff può essere applicata alle mappe, che non sembra essere il caso in Scala, chiunque è a conoscenza di qualcosa in Scala che lo renderebbe più accessibile per ottenere ciò che ottiene la funzione diff Clojure quando viene applicata alle mappe?Esiste in Scala, o in una libreria, un equivalente al diff di Clojure applicato alle mappe?

Ecco la funzione diff di Clojure spiegata per riferimento.

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

risposta

2

Come altri hanno già detto, non esiste qualcosa del genere, ma è comunque possibile costruirlo. Ecco il mio tentativo che viene aggiunto come compagno alla classe map. Produce lo stesso risultato dell'esempio del clojure diff.

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)) 
} 
1

È possibile ottenere che convertendo le mappe per elencare prima. Ad esempio:

scala> val a = Map(1->2, 2-> 3).toList 
scala> val b = Map(1->2, 3-> 4).toList 
scala> val closureDiff = List(a.diff(b), b.diff(a), a.intersect(b)) 
closureDiff: List[List[(Int, Int)]] = List(List((2,3)), List((3,4)), List((1,2))) 
+1

Questo è il più bella. Puoi riattivare gli elenchi su Maps con toMap alla fine, ad esempio 'a.diff (b) .toMap' – Gangstead

+0

. Potresti usare questo, anche se dover convertire in List è stato un po 'meno ottimale di quanto speravo. – RatavaWen

0

Non esiste alcuna funzione nella libreria standard che esegua esattamente ciò che è necessario. Tuttavia, una versione non ottimizzata può essere implementata facilmente in questo modo (mi dispiace per errore "span" al primo tentativo).

def diffffK, V: (Map [K, V], mappa [K, V], mappa [K, V]) = {

val (both,left) = m1.partition({case (k,v) => m2.get(k) == Some(v) }) 
val right = m2.filter({case (k,v) => both.get(k) != Some(v) }) 
(both,left,right) 

}

anche, una mappa può essere convertiti in un set con un singolo operatore (toSet) e quindi è possibile utilizzare gli operatori di intercettazione, unione e diff di Set.

+0

lo span non funziona poiché funziona solo in un singolo punto, quindi una volta che ha raggiunto un valore diverso, la coppia kv si riduce a tutti i seguenti valori come coppie kv divergenti anche se non lo sono. Ho provato a giocare in giro con parziali e ciò potrebbe essere utile (separa diverse coppie di KV dal resto), ma non ho ancora capito come ottenerlo per abbinare la funzione Clojure. Ma questo mi sta aiutando a fare progressi in quella direzione. – RatavaWen

4

Ciò equivale a diff di Clojure:

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)) 
} 

può operare su qualsiasi tipo di TraversableOnce e tornerà risultati con lo stesso tipo come parametri:

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)) 
Problemi correlati