Есть ли термин для groupBy, который возвращает несколько групп?

#scala #haskell #group-by #functional-programming

#scala #haskell #группировка по #функциональное программирование

Вопрос:

Подпись типа groupBy является (на языке scala, но на самом деле не зависит от языка):

 def groupBy[K](f: A => K): Map[K, Seq[A]]
  

Я реализовал, groupBy который возвращает несколько K , так что каждую A можно поместить в несколько групп одновременно. Что-то вроде этого:

 def multiGroupBy[K](f: A => Seq[K]): Map[K, Seq[A]]
  

Я делаю что-то вроде:

 case class Animal(name: String, traits: Seq[String])

List(
  Animal("cat", Seq("nocturnal", "feline")),
  Animal("dog", Seq("canine")),
  Animal("wolf", Seq("nocturnal", "canine"))
).multiGroupBy(animal => animal.traits)

// Map(nocturnal -> List(cat, wolf), feline -> List(cat), canine -> List(dog, wolf))
  

Название multiGroupBy работает, но мне интересно, существует ли уже термин (возможно, в мире haskell?) для операции, подобной описанной выше.

Комментарии:

1. Есть ли в вашем проекте зависимость от библиотеки функционального программирования, такая как Scalaz или cats ? Если нет, вы не возражаете добавить одну? Потому что это можно решить с помощью Monoid и foldMap .

2. @MustafaSimav Да, мой проект зависит от Scalaz !

3. Не следует multiGroupBy возвращать a Map[K, Seq[A]] и not Map[K, A] ?

4. @TzachZohar Спасибо. Исправлено. На самом деле groupBy тоже пришлось вернуть Map[K, Seq[A]] .

Ответ №1:

Если у вас есть Scalaz зависимость, вы можете сделать это с помощью foldMap .

 import scalaz._
import Scalaz._

case class Animal(name: String, traits: Seq[String])

val animals = List(
  Animal("cat", Seq("nocturnal", "feline")),
  Animal("dog", Seq("canine")),
  Animal("wolf", Seq("nocturnal", "canine"))
)

val r1 = animals.foldMap(a => a.traits.map(t => t -> List(a)).toMap)
println(r1)
// Map(nocturnal -> List(Animal(cat,List(nocturnal, feline)), Animal(wolf,List(nocturnal, canine))), feline -> List(Animal(cat,List(nocturnal, feline))), canine -> List(Animal(dog,List(canine)), Animal(wolf,List(nocturnal, canine))))

val r2 = animals.foldMap(a => a.traits.map(t => t -> List(a.name)).toMap)
println(r2)
// Map(nocturnal -> List(cat, wolf), feline -> List(cat), canine -> List(dog, wolf))
  

Что мы здесь сделали, так это то, что мы создали Map[String, List[Animal]] для каждого животного в списке animals и позволили Monoid[Map[String, List[Animal]]] объединить все карты.

Например, Animal("cat", Seq("nocturnal", "feline")) превратился в Map("nocturnal" -> List(Animal("cat", Seq("nocturnal", "feline"))), "feline" -> List(Animal("cat", Seq("nocturnal", "feline")))) .

Для дальнейшего чтения о monoid: http://eed3si9n.com/learning-scalaz/Monoid.html

Комментарии:

1. Спасибо за ваш ответ. Но то, что я хотел знать, было не реализацией такой операции (я уже реализовал ее, используя аналогичную реализацию scala groupBy ), а скорее уже существует метод для такой операции. Я почти уверен, что в scala std нет эквивалента, но мне было любопытно, существует ли общая терминология для этого в общем сообществе функционального программирования.

2. Чтобы я мог назвать свой новый метод лучше, чем multiGroupBy 😉