У меня есть следующий класс дел:
case class GHUser(login:String, contributions:Option[Int])
И список таких элементов:
val list = List(
List(GHUser("a", Some(10)), GHUser("b", Some(10))), List(GHUser("b", Some(300)))
).flatten
А теперь я хотел бы объединить все элементы так, чтобы все вклады были добавленывместе для одного и того же пользователя. Сначала я подумал, что могу применить Monoid к своему классу дел, например:
trait Semigroup[A] {
def combine(x: A, y: A): A
}
trait Monoid[A] extends Semigroup[A] {
def empty: A
}
case class GHUser(login: String, contributions: Option[Int])
object Main extends App {
val ghMonoid: Monoid[GHUser] = new Monoid[GHUser] {
def empty: GHUser = GHUser("", None)
def combine(x: GHUser, y: GHUser): GHUser = {
x match {
case GHUser(_, None) => GHUser(y.login, y.contributions)
case GHUser(_, Some(xv)) =>
y match {
case GHUser(_, None) => GHUser(x.login, x.contributions)
case GHUser(_, Some(yv)) => GHUser(x.login, Some(xv + yv))
}
}
}
}
val list = List(
List(GHUser("a", Some(10)), GHUser("b", Some(10))), List(GHUser("b", Some(300)))
).flatten
val b = list.groupBy(_.login)
val c = b.mapValues(_.foldLeft(ghMonoid.empty)(ghMonoid.combine))
println(c.valuesIterator mkString("\n"))
// GHUser(a,Some(10))
// GHUser(b,Some(310))
}
И это работает, но я чувствую, что не следую Законам Monoid, так как требуется, чтобы все пользователи имелитот же login
(По этой причине я сделал groupBy
звонок.
Есть ли более чистое решение?
Обновление
Перечитывая мой вопрос, кажется, что я делаюне хочу Monoid
а Semigroup
, я прав?