Hi am doing a little task, but i am new in haskell and need some help.
I have a [[(String, Int)]] which looks like this:
race :: [[(String, Int)]]
race = [[("Verstappen",25),("Perez",18),("Leclerc",15),("Russell",12),("Sainz",10),("Hamilton",8),("Norris",6),("Ocon",4),("Alonso",2),("Bottas",1),("Vettel",0),("Ricciardo",0),("Gasly",0),("Magnussen",0),("Stroll",0),("Schumacher",0),("Tsunoda",0),("Zhou",0),("Albon",0),("Latifi",0)]
,[("Verstappen",25),("Perez",18),("Leclerc",15),("Ocon",12),("Hamilton",10),("Vettel",8),("Alonso",6),("Russell",4),("Latifi",2),("Norris",1),("Ricciardo",0),("Stroll",0),("Tsunoda",0),("Magnussen",0),("Bottas",0),("Zhou",0),("Schumacher",0),("Gasly",0),("Sainz",0),("Albon",0)]
,[("Perez",25),("Verstappen",18),("Leclerc",15),("Russell",12),("Sainz",10),("Hamilton",8),("Norris",6),("Ocon",4),("Alonso",2),("Bottas",1),("Vettel",0),("Ricciardo",0),("Gasly",0),("Magnussen",0),("Stroll",0),("Schumacher",0),("Tsunoda",0),("Zhou",0),("Albon",0),("Latifi",0)]]
This is a results of 3 races. I need to count all point according to name and sort them according to points. In the end it have to be pure [String]. I was trying to made it by pattern matching but I am lost, so I will be gratefull if u will help me.
CodePudding user response:
This is a great place to apply Data.List.sortBy
and Data.List.groupBy
.
To flatten the list of lists you can use a list comprehension.
[y | x <- race, y <- x]
-- [("Verstappen",25),("Perez",18),("Leclerc",15),("Russell",12),("Sainz",10),("Hamilton",8),("Norris",6),("Ocon",4),("Alonso",2),("Bottas",1),("Vettel",0),("Ricciardo",0),("Gasly",0),("Magnussen",0),("Stroll",0),("Schumacher",0),("Tsunoda",0),("Zhou",0),("Albon",0),("Latifi",0),("Verstappen",25),("Perez",18),("Leclerc",15),("Ocon",12),("Hamilton",10),("Vettel",8),("Alonso",6),("Russell",4),("Latifi",2),("Norris",1),("Ricciardo",0),("Stroll",0),("Tsunoda",0),("Magnussen",0),("Bottas",0),("Zhou",0),("Schumacher",0),("Gasly",0),("Sainz",0),("Albon",0),("Perez",25),("Verstappen",18),("Leclerc",15),("Russell",12),("Sainz",10),("Hamilton",8),("Norris",6),("Ocon",4),("Alonso",2),("Bottas",1),("Vettel",0),("Ricciardo",0),("Gasly",0),("Magnussen",0),("Stroll",0),("Schumacher",0),("Tsunoda",0),("Zhou",0),("Albon",0),("Latifi",0)]
We can pass this to sortBy
to sort them by the names.
sortBy (\(a,_) (b,_) -> a `compare` b) [y | x <- race, y <- x]
-- [("Albon",0),("Albon",0),("Albon",0),("Alonso",2),("Alonso",6),("Alonso",2),("Bottas",1),("Bottas",0),("Bottas",1),("Gasly",0),("Gasly",0),("Gasly",0),("Hamilton",8),("Hamilton",10),("Hamilton",8),("Latifi",0),("Latifi",2),("Latifi",0),("Leclerc",15),("Leclerc",15),("Leclerc",15),("Magnussen",0),("Magnussen",0),("Magnussen",0),("Norris",6),("Norris",1),("Norris",6),("Ocon",4),("Ocon",12),("Ocon",4),("Perez",18),("Perez",18),("Perez",25),("Ricciardo",0),("Ricciardo",0),("Ricciardo",0),("Russell",12),("Russell",4),("Russell",12),("Sainz",10),("Sainz",0),("Sainz",10),("Schumacher",0),("Schumacher",0),("Schumacher",0),("Stroll",0),("Stroll",0),("Stroll",0),("Tsunoda",0),("Tsunoda",0),("Tsunoda",0),("Verstappen",25),("Verstappen",25),("Verstappen",18),("Vettel",0),("Vettel",8),("Vettel",0),("Zhou",0),("Zhou",0),("Zhou",0)]
And then groupBy
.
groupBy (\(a,_) (b,_) -> a == b) $ sortBy (\(a,_) (b,_) -> a `compare` b) [y | x <- race, y <- x]
-- [[("Albon",0),("Albon",0),("Albon",0)],[("Alonso",2),("Alonso",6),("Alonso",2)],[("Bottas",1),("Bottas",0),("Bottas",1)],[("Gasly",0),("Gasly",0),("Gasly",0)],[("Hamilton",8),("Hamilton",10),("Hamilton",8)],[("Latifi",0),("Latifi",2),("Latifi",0)],[("Leclerc",15),("Leclerc",15),("Leclerc",15)],[("Magnussen",0),("Magnussen",0),("Magnussen",0)],[("Norris",6),("Norris",1),("Norris",6)],[("Ocon",4),("Ocon",12),("Ocon",4)],[("Perez",18),("Perez",18),("Perez",25)],[("Ricciardo",0),("Ricciardo",0),("Ricciardo",0)],[("Russell",12),("Russell",4),("Russell",12)],[("Sainz",10),("Sainz",0),("Sainz",10)],[("Schumacher",0),("Schumacher",0),("Schumacher",0)],[("Stroll",0),("Stroll",0),("Stroll",0)],[("Tsunoda",0),("Tsunoda",0),("Tsunoda",0)],[("Verstappen",25),("Verstappen",25),("Verstappen",18)],[("Vettel",0),("Vettel",8),("Vettel",0)],[("Zhou",0),("Zhou",0),("Zhou",0)]]
From there you can create a tuple for each result from the name, and the sum of the scores.
[(fst $ lst !! 0, sum $ map snd lst) | lst <- groupBy (\(a,_) (b,_) -> a == b) $ sortBy (\(a,_) (b,_) -> a `compare` b) [y | x <- race, y <- x]]
-- [("Albon",0),("Alonso",10),("Bottas",2),("Gasly",0),("Hamilton",26),("Latifi",2),("Leclerc",45),("Magnussen",0),("Norris",13),("Ocon",20),("Perez",61),("Ricciardo",0),("Russell",28),("Sainz",20),("Schumacher",0),("Stroll",0),("Tsunoda",0),("Verstappen",68),("Vettel",8),("Zhou",0)]
As noted in comments, the sortOn
and groupOn
functions in Data.List.Extra
clean up the code considerably.
As well, concat
can be used to flatten the list of lists.
groupOn fst $ sortOn fst $ concat race
Manipulating this data and formatting it further is left as an exercise for the reader.