Ale Maier
Ale Maier

Reputation: 31

How to groupby categories in haskell?

Well i've this movies (peliculas in spanish) so i need to groupby categories (Fiction,Scare,Drama,Suspense,Comedy,Action).

This is how my data movie looks like:

data Pelicula = Pelicula
  { _id          :: Int
  , _titulo      :: String
  , _alquilada   :: Bool
  , _videoclub   :: V.VideoClub
  , _categoria   :: String
  } deriving Show

The categories "Attribute" is a String, so if i've this list of movies:

pelicula1  = Pelicula 1   "Inception"                         True      V.videoclub1      "Ficcion"
pelicula2  = Pelicula 2   "Inception"                         True      V.videoclub2      "Ficcion"
pelicula3  = Pelicula 3   "Inception"                         True      V.videoclub1      "Ficcion"
pelicula4  = Pelicula 4   "The Call"                          True      V.videoclub1      "Miedo"
pelicula5  = Pelicula 5   "Frozen"                            True      V.videoclub2      "Fantasia"
pelicula6  = Pelicula 6   "Fight Club"                        False     V.videoclub2      "Accion"
pelicula7  = Pelicula 7   "Now you see me"                    False     V.videoclub1      "Suspenso"
pelicula8  = Pelicula 8   "Frozen"                            False     V.videoclub1      "Fantasia"
pelicula9  = Pelicula 9   "The Call"                          False     V.videoclub2      "Miedo"
pelicula10 = Pelicula 10  "Up"                                True      V.videoclub2      "Fantasia"

Movie list: peliculas = [pelicula1 , pelicula2, pelicula3, pelicula4, pelicula5, pelicula6, pelicula7, pelicula8, pelicula9, pelicula10]

1) How can i group them by the ficcion (Fiction) category? or Suspense?

2) How can i create a list of categories from the list of movies?

Upvotes: 0

Views: 83

Answers (2)

Sibi
Sibi

Reputation: 48654

How can i group them by the ficcion (Fiction) category? or Suspense?

Haskell base has a groupBy function which can be used for this purpose. You can see it's type in ghci:

λ> import Data.List (groupBy)
λ> :t groupBy
groupBy :: (a -> a -> Bool) -> [a] -> [[a]]

Let me demonstrate that with a simpler example than your (you can use the same idea to adapt it to your code):

data Test = Test { id :: Int,
                   someField :: String 
                 } deriving (Eq, Show, Ord)

sampleData = [Test 1 "hello", Test 2 "World", Test 3 "hello", Test 4 "World"]

groupFunction :: Test -> Test -> Bool
groupFunction t1 t2 = someField t1 == someField t2

The groupFunction will be what you will be using for performing the actual grouping. Demo in ghci:

λ> groupBy groupFunction $ sortBy (\x y -> someField x `compare` someField y) sampleData 
[[Test {id = 2, someField = "World"},Test {id = 4, someField = "World"}],[Test {id = 1, someField = "hello"},Test {id = 3, someField = "hello"}]]

You can adapt this to your use case.

Upvotes: 2

Nikita Volkov
Nikita Volkov

Reputation: 43310

The following code implements a utility function, which can be applied to your problem:

import qualified Data.Map as Map -- from the "containers" library

groupToMap :: (Ord b) => (a -> b) -> [a] -> Map.Map b [a]
groupToMap toKey =
  Map.fromListWith (++) . map (\a -> (toKey a, [a]))

Using that function now you can group your data easily:

groupPeliculas :: [Pelicula] -> Map.Map String [Pelicula]
groupPeliculas =
  groupToMap _categoria

Extracting a list of categories is not any less trivial:

peliculaCategories :: [Pelicula] -> [String]
peliculaCategories =
  map _categoria

If you need to get a list of unique items, do it this way:

import qualified Data.List as List

peliculaCategories :: [Pelicula] -> [String]
peliculaCategories =
  List.nub . map _categoria

But then it'll be smarter to use the Set datastructure for that:

import qualified Data.Set as Set

peliculaCategories :: [Pelicula] -> Set.Set String
peliculaCategories =
  foldr Set.insert Set.empty . map _categoria

Upvotes: 2

Related Questions