如何在Scala中编写此递归groupBy函数

如何在Scala中编写此递归groupBy函数,scala,recursion,types,Scala,Recursion,Types,最近,我遇到了Groovy在Iterable上提供的一个非常有用的groupBy函数: public static Map groupBy(Iterable self, List<Closure> closures) 另外,我如何用正确的类型实现递归 这是一个简单的多组实现: implicit class GroupOps[A](coll: Seq[A]) { def groupByKeys[B](fs: (A => B)*): Map[Seq[B], Seq[A]] =

最近,我遇到了Groovy在Iterable上提供的一个非常有用的groupBy函数:

public static Map groupBy(Iterable self, List<Closure> closures)

另外,我如何用正确的类型实现递归

这是一个简单的多组实现:

implicit class GroupOps[A](coll: Seq[A]) {
  def groupByKeys[B](fs: (A => B)*): Map[Seq[B], Seq[A]] =
    coll.groupBy(elem => fs map (_(elem)))
}

val a = 1 to 20

a.groupByKeys(_ % 3, _ % 2) foreach println
如果您确实需要某种递归类型,则需要一个包装器:

sealed trait RecMap[K, V]

case class MapUnit[K, V](elem: V) extends RecMap[K, V] {
  override def toString = elem.toString()
}
case class MapLayer[K, V](map: Map[K, RecMap[K, V]]) extends RecMap[K, V] {
  override def toString = map.toString()
}
将定义更改为:

implicit class GroupOps[A](coll: Seq[A]) {
  def groupByKeys[B](fs: (A => B)*): Map[Seq[B], Seq[A]] =
    coll.groupBy(elem => fs map (_(elem)))

  def groupRecursive[B](fs: (A => B)*): RecMap[B, Seq[A]] = fs match {
    case Seq() => MapUnit(coll)
    case f +: fs => MapLayer(coll groupBy f mapValues {_.groupRecursive(fs: _*)})
  }
}
而a.groupRecursive%3,%2产生了与问题更相关的东西

最后,我根据参考文章重建域定义:

case class User(name: String, city: String, birthDate: Date) {
  override def toString = name
}

implicit val date = new SimpleDateFormat("yyyy-MM-dd").parse(_: String)
val month = new SimpleDateFormat("MMM").format (_:Date)

val users = List(
  User(name = "mrhaki", city = "Tilburg"  , birthDate = "1973-9-7"),
  User(name = "bob"   , city = "New York" , birthDate = "1963-3-30"),
  User(name = "britt" , city = "Amsterdam", birthDate = "1980-5-12"),
  User(name = "kim"   , city = "Amsterdam", birthDate = "1983-3-30"),
  User(name = "liam"  , city = "Tilburg"  , birthDate = "2009-3-6")
)
现在我们可以写作了

users.groupRecursive(_.city, u => month(u.birthDate))
得到

MapTilburg->MapMar->Listliam,九月->Listmrhaki,纽约 ->MapMar->Listbob,阿姆斯特丹->MapMar->Listkim,May->Listbritt


这是一个简单的多组实现:

implicit class GroupOps[A](coll: Seq[A]) {
  def groupByKeys[B](fs: (A => B)*): Map[Seq[B], Seq[A]] =
    coll.groupBy(elem => fs map (_(elem)))
}

val a = 1 to 20

a.groupByKeys(_ % 3, _ % 2) foreach println
如果您确实需要某种递归类型,则需要一个包装器:

sealed trait RecMap[K, V]

case class MapUnit[K, V](elem: V) extends RecMap[K, V] {
  override def toString = elem.toString()
}
case class MapLayer[K, V](map: Map[K, RecMap[K, V]]) extends RecMap[K, V] {
  override def toString = map.toString()
}
将定义更改为:

implicit class GroupOps[A](coll: Seq[A]) {
  def groupByKeys[B](fs: (A => B)*): Map[Seq[B], Seq[A]] =
    coll.groupBy(elem => fs map (_(elem)))

  def groupRecursive[B](fs: (A => B)*): RecMap[B, Seq[A]] = fs match {
    case Seq() => MapUnit(coll)
    case f +: fs => MapLayer(coll groupBy f mapValues {_.groupRecursive(fs: _*)})
  }
}
而a.groupRecursive%3,%2产生了与问题更相关的东西

最后,我根据参考文章重建域定义:

case class User(name: String, city: String, birthDate: Date) {
  override def toString = name
}

implicit val date = new SimpleDateFormat("yyyy-MM-dd").parse(_: String)
val month = new SimpleDateFormat("MMM").format (_:Date)

val users = List(
  User(name = "mrhaki", city = "Tilburg"  , birthDate = "1973-9-7"),
  User(name = "bob"   , city = "New York" , birthDate = "1963-3-30"),
  User(name = "britt" , city = "Amsterdam", birthDate = "1980-5-12"),
  User(name = "kim"   , city = "Amsterdam", birthDate = "1983-3-30"),
  User(name = "liam"  , city = "Tilburg"  , birthDate = "2009-3-6")
)
现在我们可以写作了

users.groupRecursive(_.city, u => month(u.birthDate))
得到

MapTilburg->MapMar->Listliam,九月->Listmrhaki,纽约 ->MapMar->Listbob,阿姆斯特丹->MapMar->Listkim,May->Listbritt


由于方法完全不同,我决定添加另一个答案

实际上,您可以使用大量变通方法获得非包装的正确类型的地图。我不太擅长这个,所以碰巧可以简化一下

诀窍是创建类型化函数序列,该序列最近使用类型类和类型路径方法生成多级映射

这就是解决方案

sealed trait KeySeq[-V] {
  type values
}

case class KeyNil[V]() extends KeySeq[V] {
  type values = Seq[V]
}

case class KeyCons[K, V, Next <: KeySeq[V]](f: V => K, next: Next)
                                           (implicit ev: RecGroup[V, Next]) extends KeySeq[V] {
  type values = Map[K, Next#values]

  def #:[K1](f: V => K1) = new KeyCons[K1, V, KeyCons[K, V, Next]](f, this)
}

trait RecGroup[V, KS <: KeySeq[V]] {
  def group(seq: Seq[V], ks: KS): KS#values
}

implicit def groupNil[V]: RecGroup[V, KeyNil[V]] = new RecGroup[V, KeyNil[V]] {
  def group(seq: Seq[V], ks: KeyNil[V]) = seq
}

implicit def groupCons[K, V, Next <: KeySeq[V]](implicit ev: RecGroup[V, Next]): RecGroup[V, KeyCons[K, V, Next]] =
  new RecGroup[V, KeyCons[K, V, Next]] {
    def group(seq: Seq[V], ks: KeyCons[K, V, Next]) = seq.groupBy(ks.f) mapValues (_ groupRecursive ks.next)
  }



implicit def funcAsKey[K, V](f: V => K): KeyCons[K, V, KeyNil[V]] =
  new KeyCons[K, V, KeyNil[V]](f, KeyNil[V]())

implicit class GroupOps[V](coll: Seq[V]) {
  def groupRecursive[KS <: KeySeq[V]](ks: KS)(implicit g: RecGroup[V, KS]) =
    g.group(coll, ks)
}
然后

将产生正确的映射[布尔,映射[Int,映射[Int,Int]]

如果从前面的问题我们想

users.groupRecursive(((u:User)=> u.city(0)) #: ((u:User) => month(u.birthDate)))

我们正在构建Map[Char,Map[String,User]

由于方法完全不同,我决定添加另一个答案

实际上,您可以使用大量变通方法获得非包装的正确类型的地图。我不太擅长这个,所以碰巧可以简化一下

诀窍是创建类型化函数序列,该序列最近使用类型类和类型路径方法生成多级映射

这就是解决方案

sealed trait KeySeq[-V] {
  type values
}

case class KeyNil[V]() extends KeySeq[V] {
  type values = Seq[V]
}

case class KeyCons[K, V, Next <: KeySeq[V]](f: V => K, next: Next)
                                           (implicit ev: RecGroup[V, Next]) extends KeySeq[V] {
  type values = Map[K, Next#values]

  def #:[K1](f: V => K1) = new KeyCons[K1, V, KeyCons[K, V, Next]](f, this)
}

trait RecGroup[V, KS <: KeySeq[V]] {
  def group(seq: Seq[V], ks: KS): KS#values
}

implicit def groupNil[V]: RecGroup[V, KeyNil[V]] = new RecGroup[V, KeyNil[V]] {
  def group(seq: Seq[V], ks: KeyNil[V]) = seq
}

implicit def groupCons[K, V, Next <: KeySeq[V]](implicit ev: RecGroup[V, Next]): RecGroup[V, KeyCons[K, V, Next]] =
  new RecGroup[V, KeyCons[K, V, Next]] {
    def group(seq: Seq[V], ks: KeyCons[K, V, Next]) = seq.groupBy(ks.f) mapValues (_ groupRecursive ks.next)
  }



implicit def funcAsKey[K, V](f: V => K): KeyCons[K, V, KeyNil[V]] =
  new KeyCons[K, V, KeyNil[V]](f, KeyNil[V]())

implicit class GroupOps[V](coll: Seq[V]) {
  def groupRecursive[KS <: KeySeq[V]](ks: KS)(implicit g: RecGroup[V, KS]) =
    g.group(coll, ks)
}
然后

将产生正确的映射[布尔,映射[Int,映射[Int,Int]]

如果从前面的问题我们想

users.groupRecursive(((u:User)=> u.city(0)) #: ((u:User) => month(u.birthDate)))

我们正在构建Map[Char,Map[String,User]

太棒了!不知道递归类型。非常感谢,太棒了!不知道递归类型。非常感谢。