【问题标题】:Zip two HashMaps(or dictionaries)压缩两个 HashMap(或字典)
【发布时间】:2013-04-21 21:56:21
【问题描述】:

在 Scala 中压缩两个字典的实用方法是什么?

map1 = new HashMap("A"->1,"B"->2)
map2 = new HashMap("B"->22,"D"->4) // B is the only common key

zipper(map1,map2) 应该给出类似于

 Seq( ("A",1,0), // no A in second map, so third value is zero
      ("B",2,22),
      ("D",0,4)) // no D in first map, so second value is zero 

如果没有功能,任何其他风格也很受欢迎

【问题讨论】:

  • Haskell 的 Data.Map 有一个很棒的组合器,叫做unionWith,它可以让这个过程变得非常简单。它和它的交集对应物非常有用,我很遗憾它们仅在 Scala 的 IntMapLongMap 中可用(主要是因为它们是从 Haskell 翻译过来的,我预计)。
  • @copumpkin:Haskell 太棒了!我将检查 unionWith。我刚刚检查了 IntMap,它现在被 HashMap 从 2.8 取代
  • 它并没有真正被 HashMap 取代,尽管文档评论表明了这一点。它们是不同的结构,IntMap 具有不同的属性。有时您真的不希望在其中使用散列函数,尤其是当您想要维护数据的顺序时。 IntMap 主要可以实现SortedMap,但我认为现在还不行。一个问题是它遵循“未签名”的顺序,但如果你需要的话,让它表现得像一个签名的顺序并不难。

标签: scala map functional-programming


【解决方案1】:
def zipper(map1: Map[String, Int], map2: Map[String, Int]) = {
  for(key <- map1.keys ++ map2.keys)
    yield (key, map1.getOrElse(key, 0), map2.getOrElse(key, 0))
}


scala> val map1 = scala.collection.immutable.HashMap("A" -> 1, "B" -> 2)
map1: scala.collection.immutable.HashMap[String,Int] = Map(A -> 1, B -> 2)

scala> val map2 = scala.collection.immutable.HashMap("B" -> 22, "D" -> 4)
map2: scala.collection.immutable.HashMap[String,Int] = Map(B -> 22, D -> 4)

scala> :load Zipper.scala
Loading Zipper.scala...
zipper: (map1: Map[String,Int], map2: Map[String,Int])Iterable[(String, Int, Int)]

scala> zipper(map1, map2)
res1: Iterable[(String, Int, Int)] = Set((A,1,0), (B,2,22), (D,0,4))

注意在这种情况下使用get 可能比getOrElse 更可取。 None 用于指定某个值不存在,而不是使用0

【讨论】:

  • 有什么方法可以获取类型参数的“零”吗?除了那些讨厌的'0'之外,拉链可以通用
  • 我不确定这是否是概括的正确方向,但您可以查看Monoid,它有一个(关联)操作和一个零。零本身没有多大意义,因为使它成为零的是它与其他事物的交互方式。正如我在其他评论中所建议的那样,我认为unionWith[A,B](x: Map[A,B], y: Map[A,B])(f: (B, B) =&gt; B): Map[A, B] 是这里的理想方法。组合功能仅在重叠时使用,因此您甚至不需要零的概念。更一般的:unionWith[K,A,B,C])(x: Map[K,A], y: Map[K,B])(l: A =&gt; C, r: B =&gt; C, b: (A,B) =&gt; C): Map[K,C].
  • 请注意,仅当您想“记住”两侧之一丢失时才需要更通用的一个,并且实际上等效于在两个输入上都使用 mapValues 并将它们扔到 @ 987654330@ 在调用不太通用的unionWith 之前。再深入一点,如果您认为Map 只是一个表示K =&gt; Option[V] 的有效数据结构,那么各种选项只是K =&gt; _ monad 本质的变体。我之所以说本质是因为Map 不能完全用作Monad/Applicative,但如果你放弃return/pure 它可以。
【解决方案2】:

作为 Brian 的答案的替代方案,这可用于通过隐式方法增强地图类:

implicit class MapUtils[K, +V](map: collection.Map[K, V]) {
  def zipAllByKey[B >: V, C >: V](that: collection.Map[K, C], thisElem: B, thatElem: C): Iterable[(K, B, C)] =
  for (key <- map.keys ++ that.keys)
    yield (key, map.getOrElse(key, thisElem), that.getOrElse(key, thatElem))
}

命名和API类似于序列zipAll

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多