Home > Blockchain >  Counting second element in tuple according to first element and sort them
Counting second element in tuple according to first element and sort them

Time:10-17

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.

  • Related