使用复杂(双重)操作合并 scalaz 中的地图 [英] Merge maps in scalaz with a complex (double) operation

查看:39
本文介绍了使用复杂(双重)操作合并 scalaz 中的地图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用地图将某些值与元组 (Int, Double) 相关联,其中 int 是它们出现的顺序,是它们显示次数的两倍(不是,但使用 int 和双重区分)

I am using a map to associate certain values with a tuple (Int, Double) where the int is the order they appeared and the double the number of times they show (it is not, but is clearer like this using int and double to distinguish)

棘手的部分是我想为元组的每个元素使用不同的幺半群,对于 int 我想保持最小值,记住第一次出现,而对于双精度我想使用加法幺半群因此,对于现有的密钥,我们有:

The tricky part is that I want to use different monoids for each element of the tuple, for the int I want to keep the min value, to remember first appearance, while for the double I want to use the addition monoid So for an existing key we have:

val map1 = Map("a" -> (1, 5.0), "b" -> (2, 4.0), "c" -> (3, 8.0))
val map2 = Map("b" -> (4, 1.0))

val merge = map1.toMap |+| map2.toMap
// Map(a -> (1, 5.0), b -> (2, 5.0), c -> (3, 8.0))

对于一个新的密钥,我们有:

And for a new key we have:

val map2 = Map("d" -> (4, 1.0))

val merge2 = map1.toMap |+| map2.toMap
// Map(a -> (1, 5.0), b -> (2, 4.0), c -> (3, 8.0), d -> (4, 1.0))

我找不到办法做到这一点,我显然可以使用加法幺半群,我可以使用 minval 一个,但我看不出如何组合它们.任何帮助表示赞赏!谢谢

I can not find a way do this, i can obviously use the addition monoid, and i can use the minval one, but i can not see how to combine them. Any help appreciated! thanks

推荐答案

您可以将 scalaz.std.tuple.tuple2Monoid 明确用于您想要的两个幺半群:

You can use scalaz.std.tuple.tuple2Monoid explicitly with the two monoids you want:

import scalaz.Monoid

implicit val countMonoid: Monoid[(Int, Double)] = scalaz.std.tuple.tuple2Monoid(
  Monoid.instance[Int](math.min(_, _), Int.MaxValue),
  Monoid.instance[Double](_ + _, 0)
)

然后:

scala> import scalaz.std.map._, scalaz.syntax.monoid._
import scalaz.std.map._
import scalaz.syntax.monoid._

scala> val map1 = Map("a" -> (1, 5.0), "b" -> (2, 4.0), "c" -> (3, 8.0))
map1: scala.collection.immutable.Map[String,(Int, Double)] = Map(a -> (1,5.0), b -> (2,4.0), c -> (3,8.0))

scala> val map2 = Map("b" -> (4, 1.0))
map2: scala.collection.immutable.Map[String,(Int, Double)] = Map(b -> (4,1.0))

scala> val merge = map1.toMap |+| map2.toMap
merge: scala.collection.immutable.Map[String,(Int, Double)] = Map(a -> (1,5.0), b -> (2,5.0), c -> (3,8.0))
scala> val map2 = Map("d" -> (4, 1.0))
map2: scala.collection.immutable.Map[String,(Int, Double)] = Map(d -> (4,1.0))

scala> val merge2 = map1.toMap |+| map2.toMap
merge2: scala.collection.immutable.Map[String,(Int, Double)] = Map(a -> (1,5.0), b -> (2,4.0), c -> (3,8.0), d -> (4,1.0))

不过,这并不理想,因为类型 (Int, Double) 可用于表示许多不同的事物,而您刚刚定义了一个可能出现的幺半群实例在您或您的用户不期望的地方.我个人会改用案例类:

This isn't really ideal, though, since the type (Int, Double) can be used to represent lots of different things, and you've just defined a monoid instance that might turn up in places you or your users don't expect. Personally I'd use a case class instead:

case class Count(order: Int, number: Double)

然后在 Count 伴随对象中定义实例,显式或通过上面的 countMonoid 和一个 IsoSet[Count, (Int, Double)].

And then define the instance in the Count companion object, either explicitly or via the countMonoid above and an IsoSet[Count, (Int, Double)].

这篇关于使用复杂(双重)操作合并 scalaz 中的地图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆