1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
module Candidate(
Ranking,
Position,
CandidateID,
AboveLineBallot,
BelowLineBallot,
readCandidates
) where
import qualified CSV as CSV
import qualified Miscellaneous as Misc
import qualified System.IO as IO
import qualified Data.List as List
import qualified Data.Either.Unwrap as Either
import qualified Data.Maybe as Maybe
type Ranking = Int
type Position = Int
type CandidateID = String
-- positions in the uppermap list correspond to the boxes above the line,
-- and the lists of candidateIDs are the boxes below the line
type AboveLineBallot = [[Position]]
-- a list of candidates in the order of how they were placed below the line
type BelowLineBallot = [CandidateID]
readCandidates :: FilePath -> String -> IO (AboveLineBallot, BelowLineBallot)
readCandidates inputFile state = do
h <- IO.openFile inputFile IO.ReadMode
e <- IO.hIsEOF h
let readFunc r c = if c then return r else do
t0 <- IO.hGetLine h
let t1 = CSV.parseRecord CSV.defaultSettings t0
t2 = Misc.selectFrom [5,6,7,8,9] [(2,"S"),(3,state)] (Either.fromRight t1)
t3 = Maybe.fromJust t2
tx <- IO.hIsEOF h
if (Either.isRight t1) && (Maybe.isJust t2)
then readFunc (t3:r) tx
else readFunc r tx
raw <- readFunc [] e >>= return . (List.sort)
IO.hClose h
return (makeAboveBallot raw, makeBelowBallot raw)
-- very hacky, pls revise
makeAboveBallot :: [[String]] -> AboveLineBallot
makeAboveBallot input =
let comp x y = (head x) == (head y)
grouped = List.groupBy comp (filter ((/= "UG") . head) input)
numFunc n r t =
if (t == [])
then r
else numFunc (n + (length (head t))) (r ++ [(map fst (zip [n, n+1 ..] (head t)))]) (tail t)
in numFunc (fromIntegral 1) [] grouped
makeBelowBallot :: [[String]] -> BelowLineBallot
makeBelowBallot input =
let f (_:_:c:d:e:[]) = d ++ " " ++ c ++ ", " ++ e
in map f input
|