DEV Community

Discussion on: Daily Challenge #26 - Ranking Position

Collapse
 
avalander profile image
Avalander • Edited

My solution in clumsy Haskell:

-- Data/Score.hs
module Data.Score where

data Score = Score
  { name :: String
  , points :: Int
  } deriving (Show)


compare_scores :: Score -> Score -> Ordering
compare_scores a b =
  case compare (points a) (points b) of EQ -> compare (name b) (name a)
                                        LT -> LT
                                        GT -> GT
-- Data/Rank.hs
module Data.Rank where

import Data.Score as S

data Rank = Rank
  { name :: String
  , points :: Int
  , position :: Int
  } deriving (Show)

from_score :: S.Score -> Int -> Rank
from_score score position = Rank
  { Data.Rank.name = S.name score
  , Data.Rank.points = S.points score
  , Data.Rank.position = position
  }
import Data.List (sortBy)
import Data.Rank as R
import Data.Score as S

sort_scores :: [ S.Score ] -> [ S.Score ]
sort_scores = sortBy (flip S.compare_scores)

map_to_records :: [ S.Score ] -> [ R.Rank ]
map_to_records = foldl kevin []
  where
    kevin :: [ R.Rank ] -> S.Score -> [ R.Rank ]
    kevin [] score = [ R.from_score score 1 ]
    kevin xs score
      | tied_score = xs ++ [ R.from_score score prev_position ]
      | otherwise  = xs ++ [ R.from_score score next_position ]
      where
        prev = last xs
        tied_score = R.points prev == S.points score
        prev_position = R.position prev
        next_position = (length xs) + 1

rank_scores :: [ S.Score ] -> [ R.Rank ]
rank_scores = map_to_records . sort_scores

scores :: [ S.Score ]
scores =
  [ S.Score { S.name = "John"
            , S.points =  100
            }
  , S.Score { S.name = "Bob"
            , S.points = 130
            }
  , S.Score { S.name = "Mary"
            , S.points = 120
            }
  , S.Score { S.name = "Kate"
            , S.points = 120
            }
  ]

rank_scores scores
{-[ Rank {name = "Bob", points = 130, position = 1}
  , Rank {name = "Kate", points = 120, position = 2}
  , Rank {name = "Mary", points = 120, position = 2}
  , Rank {name = "John", points = 100, position = 4}
  ]
-}