如何在功能上将String映射合并到List?

时间:2012-10-21 03:13:45

标签: scala collections map functional-programming generic-collections

我已经构建了一个这样的抽象:

class Thing(val messages: Map[String, Seq[String]]) { 
  def and(that: Thing): Thing = {
    new Thing(this.messages ++ that.messages)
  }
}

this的{​​{1}}地图需要与String -> Seq[String]地图合并。

这是我能想到的最佳方式:

that

3 个答案:

答案 0 :(得分:3)

以下是使用groupBy的版本:

def and(that: Thing): Thing = {
  new Thing(
    (this.messages.toIndexedSeq ++ that.messages)
      .groupBy(_._1)
      .map { case (k,vs) => k -> vs.flatMap(_._2) }
      .toMap)
}

答案 1 :(得分:1)

Scalaz库包含此函数,|+|(半群追加)运算符。请注意,您需要选择比Seq更具体的集合类型,即具有半群实例的集合类型,因此我使用了List

import scalaz._, Scalaz._

class Thing(val messages: Map[String, List[String]]) { 
  def and(that: Thing): Thing =
    new Thing(this.messages |+| that.messages)
}

您还可以为Thing定义半群实例,并使用|+|运算符组合Thing

case class Thing(val messages: Map[String, List[String]])

implicit val ThingSemigroup = new Semigroup[Thing] {
  def append(t1: Thing, t2: => Thing) = new Thing(t1.messages |+| t2.messages)
}

Thing(Map("foo" -> List("bar"))) |+| Thing(Map("foo" -> List("baz")))
// Thing(Map(foo -> List(bar, baz)))

答案 2 :(得分:0)

我在评论中链接的答案的更具体,略微修改的版本可能会使方法更清晰:

def and(that: Thing): Thing = {
  new Thing(this.messages.foldLeft(that.messages) { case (out, (keyToAdd, valuesToAdd)) =>
    out ++ Map(keyToAdd -> out.get(keyToAdd).map(_ ++ valuesToAdd).getOrElse(valuesToAdd))
  })
}

还具有不在其中一个地图上循环的优势。