Subdivisez vos collections avec groupBy

Leave a Comment

Récemment sur l'un de mes projets en Scala j'ai eu besoin de grouper un ensemble d'objets selon un critère donné. Il s'agissait de grouper des catégories selon le nom de leur parent. Voici une version simplifiée du modèle de données :

case class Category(id: String, name: String, parent: Option[ParentInfo])

case class ParentInfo(id: String, name: String)
Je récupère de la base de données l'ensemble des catégories et j'obtiens une collection qui ressemble à ce qui suit :
val categories = Set(
  Category("1", "Immobilier", None), 
  Category("2", "Véhicules", None), 
  Category("3", "Multimédia", None),
  Category("4", "Motos", Some(ParentInfo("2", "Véhicules"))), 
  Category("5", "Equipement auto", Some(ParentInfo("2", "Véhicules"))),   
  Category("6", "Locations", Some(ParentInfo("1", "Immobilier"))),
  Category("7", "Colocations", Some(ParentInfo("1", "Immobilier"))),
  Category("8", "Consoles et jeux vidéo", Some(ParentInfo("3", "Multimédia"))),
  Category("9", "Matériel informatique", Some(ParentInfo("3", "Multimédia")))    
)

Le premier traitement consiste à filtrer les catégories qui n'ont pas de parent :

categories.filter(cat => cat.parent != None)
Exécuté dans le REPL cela donne :
scala> categories.filter(cat => cat.parent != None)
res0: scala.collection.immutable.Set[Category] = Set(Category(6,Locations,Some(ParentInfo(1,Immobilier))), Category(5,Equipement auto,Some(ParentInfo(2,Véhicules))), Category(7,Colocations,Some(ParentInfo(1,Immobilier))), Category(8,Consoles et jeux vidéo,Some(ParentInfo(3,Multimédia))), Category(4,Motos,Some(ParentInfo(2,Véhicules))), Category(9,Matériel informatique,Some(ParentInfo(3,Multimédia))))

Enfin il suffit d'appliquer la méthode groupBy au résultat obtenu mais voyons rapidement la signature de celle-ci :

def groupBy [K] (f: (A) ⇒ K): Map[K, Traversable[A]]

Cette méthode du trait Traversable prend en paramètre une fonction qui produit les clés de groupement des éléments de la collection initiale. Le résultat de groupBy est un Map qui associe une clé, ici le nom du parent de la catégorie, à une collection d'éléments, ici des catégories filles. Tout cela se fait en une ligne grâce à la puissance des collections de Scala :

categories.filter(cat => cat.parent != None).groupBy(cat => cat.parent.get.name)
//On filtre puis on applique groupBy au résultat

Testez-le dans le REPL, ça marche!

categories.filter(cat => cat.parent != None).groupBy(cat => cat.parent.get.name)
res1: scala.collection.immutable.Map[String,scala.collection.immutable.Set[Category]] = Map(Véhicules -> Set(Category(5,Equipement auto,Some(ParentInfo(2,Véhicules))), Category(4,Motos,Some(ParentInfo(2,Véhicules)))), Immobilier -> Set(Category(6,Locations,Some(ParentInfo(1,Immobilier))), Category(7,Colocations,Some(ParentInfo(1,Immobilier)))), Multimédia -> Set(Category(8,Consoles et jeux vidéo,Some(ParentInfo(3,Multimédia))), Category(9,Matériel informatique,Some(ParentInfo(3,Multimédia)))))
© Nouhoum TRAORE.. Fourni par Blogger.