diff --git a/teams.hs b/teams.hs index 678fe8c..ea4dcba 100644 --- a/teams.hs +++ b/teams.hs @@ -6,55 +6,182 @@ import Data.Aeson.Types as AET import Data.ByteString.Lazy as BL import Data.ByteString.Lazy.Char8 as BL8 import Data.HashMap.Strict as HM +import Data.Maybe as M import Prelude as P --- "id":7, --- "key":"gam", --- "title":"Gambia", --- "title2":null, --- "code":"GAM", --- "synonyms":null, --- "country_id":43, --- "city_id":null, --- "club":"f", --- "since":null, --- "address":null, --- "web":null, --- "assoc_id":null, --- "national":"f", --- "created_at":"2016-10-16 20:00:51.702726", --- "updated_at":"2016-10-16 20:00:51.702726" - -data Team = Team { _id :: Value, country :: Value } deriving (Show) - -instance ToJSON Team where - toJSON Team{..} = object [ "i" .= _id, "c" .= country ] +----- Data constructors ----- +data TeamFinal = TeamFinal { + resultId :: Int, + resultCountry :: String, + resultContinent :: String, + resultGoals :: Int +} deriving (Show) +data Team = Team { + teamId :: Int, + teamCountryId :: Int } deriving (Show) + +data EventTeam = EventTeam { + eventTeamId :: Int } deriving (Show) + +data Country = Country { + countryId :: Int, + countryName :: String, + countryContinentId :: Int } deriving (Show) + +data Continent = Continent { + continentId :: Int, + continentName :: String } deriving (Show) + +data Game = Game { + roundId :: Int, + playAt :: String, + team1Id :: Int, + team2Id :: Int, + score1 :: Value, + score2 :: Value, + score1et :: Value, + score2et :: Value, + score1p :: Value, + score2p :: Value } deriving (Show) + +----- Type synonyms ----- +type Teams = HashMap Int Team +type Countries = HashMap Int Country +type Continents = HashMap Int Continent + +----- ToJSON parsers ----- +instance ToJSON TeamFinal where + toJSON TeamFinal{..} = + object [ "id" .= resultId, "ct" .= resultCountry, "cn" .= resultContinent, "g" .= resultGoals ] + +----- FromJSON parsers ----- instance FromJSON Team where parseJSON = withObject "team" $ \o -> do - _id <- o .: "id" - country <- o .: "title" + teamId <- o .: "id" + teamCountryId <- o .: "country_id" return Team{..} -reduce :: [Team] -> Value -> [Team] -reduce acc x = case (parseEither parseJSON x :: Either String Team) of - (Left s) -> error s - (Right v) -> v : acc +instance FromJSON EventTeam where + parseJSON = withObject "team" $ \o -> do + eventTeamId <- o .: "team_id" + return EventTeam{..} + +instance FromJSON Game where + parseJSON = withObject "game" $ \o -> do + roundId <- o .: "round_id" + team1Id <- o .: "team1_id" + team2Id <- o .: "team2_id" + playAt <- o .: "play_at" + score1 <- o .: "score1" + score2 <- o .: "score2" + score1et <- o .: "score1et" + score2et <- o .: "score2et" + score1p <- o .: "score1p" + score2p <- o .: "score2p" + return Game{..} -parseTeams :: Either String [Value] -> [Team] +instance FromJSON Country where + parseJSON = withObject "country" $ \o -> do + countryId <- o .: "id" + countryName <- o .: "name" + countryContinentId <- o .: "continent_id" + return Country{..} + +instance FromJSON Continent where + parseJSON = withObject "continent" $ \o -> do + continentId <- o .: "id" + continentName <- o .: "name" + return Continent{..} + +parseTeams :: Either String [Value] -> Teams parseTeams (Left x) = error x -parseTeams (Right xs) = P.foldl reduce [] xs +parseTeams (Right xs) = P.foldl reduce HM.empty xs where + reduce acc x = case (parseEither parseJSON x :: Either String Team) of + (Left s) -> error s + (Right v) -> HM.insert (teamId v) v acc + +parseEventTeams :: Either String [Value] -> [Int] +parseEventTeams (Left x) = error x +parseEventTeams (Right xs) = P.foldl reduce [] xs where + reduce acc x = case (parseEither parseJSON x :: Either String EventTeam) of + (Left s) -> error s + (Right v) -> eventTeamId v : acc -parseResult :: [Team] -> [(String, Value)] -parseResult = P.foldl (\acc x -> (extractId x, country x) : acc) [] - where - extractId = BL8.unpack . encode . _id +parseGames :: Either String [Value] -> [Game] +parseGames (Left x) = error x +parseGames (Right xs) = P.foldl reduce [] xs where + reduce acc x = case (parseEither parseJSON x :: Either String Game) of + (Left s) -> error s + (Right v) -> v : acc + +parseCountries :: Either String [Value] -> Countries +parseCountries (Left x) = error x +parseCountries (Right xs) = P.foldl reduce HM.empty xs where + reduce acc x = case (parseEither parseJSON x :: Either String Country) of + (Left s) -> error s + (Right v) -> HM.insert (countryId v) v acc + +parseContinents :: Either String [Value] -> Continents +parseContinents (Left x) = error x +parseContinents (Right xs) = P.foldl reduce HM.empty xs where + reduce acc x = case (parseEither parseJSON x :: Either String Continent) of + (Left s) -> error s + (Right v) -> HM.insert (continentId v) v acc + +parseInt :: Value -> Int +parseInt Null = 0 +parseInt x = read $ BL8.unpack $ encode x :: Int + +----- Hashmap lookup convenience ----- +lookupTeam :: Int -> Teams -> Team +lookupTeam _id hm = M.fromMaybe (Team 999 999) (HM.lookup _id hm) + +lookupCountry :: Int -> Countries -> Country +lookupCountry _id hm = M.fromMaybe (Country 999 "Unknown" 999) (HM.lookup _id hm) + +lookupContinent :: Int -> Continents -> Continent +lookupContinent _id hm = M.fromMaybe (Continent 999 "Unknown") (HM.lookup _id hm) + +countryFromTeamId :: Int -> Teams -> Countries -> Country +countryFromTeamId _id hmT = lookupCountry a where + a = teamCountryId $ lookupTeam _id hmT + +continentFromTeamId :: Int -> Teams -> Countries -> Continents -> Continent +continentFromTeamId _id hmT hmC = lookupContinent (countryContinentId b) where + a = teamCountryId $ lookupTeam _id hmT + b = lookupCountry a hmC + +goalsFromTeamId :: Int -> [Game] -> Int +goalsFromTeamId _id = P.foldl reducer 0 where + reducer acc x + | team1Id x == _id = acc + parseInt (score1 x) + parseInt (score1et x) + parseInt (score1p x) + | team2Id x == _id = acc + parseInt (score2 x) + parseInt (score2et x) + parseInt (score2p x) + | otherwise = acc + +buildResult :: [Int] -> Teams -> Countries -> Continents -> [Game] -> [TeamFinal] +buildResult ets hmT hmC hmN gs = P.foldl reducer [] ets where + reducer acc x = TeamFinal x (getCountryName x) (getContinentName x) (goalCount x) : acc + getCountryName x = countryName (countryFromTeamId x hmT hmC) + getContinentName x = continentName (continentFromTeamId x hmT hmC hmN) + goalCount x = goalsFromTeamId x gs main :: IO () main = do - src <- BL.readFile "./data/teams.json" - let teams = parseTeams (AE.eitherDecode src :: Either String [Value]) - let encoded = encode $ HM.fromList $ parseResult teams + dataTeams <- BL.readFile "./data/teams.json" + dataEventTeams <- BL.readFile "./data/events_teams.json" + dataCountries <- BL.readFile "./data/countries.json" + dataContinents <- BL.readFile "./data/continents.json" + dataGames <- BL.readFile "./data/games.json" + + let teams = parseTeams (AE.eitherDecode dataTeams) + let eventteams = parseEventTeams (AE.eitherDecode dataEventTeams) + let games = parseGames (AE.eitherDecode dataGames) + let countries = parseCountries (AE.eitherDecode dataCountries) + let continents = parseContinents (AE.eitherDecode dataContinents) + + let encoded = encode $ buildResult eventteams teams countries continents games BL8.putStrLn encoded - BL8.putStrLn "Writing games.json" + P.putStrLn $ show (P.length eventteams) ++ " teams found." + BL8.putStrLn "Writing teams.json" BL8.writeFile "teams.json" encoded diff --git a/teams.json b/teams.json index c7753a9..a99d6a9 100644 --- a/teams.json +++ b/teams.json @@ -1 +1 @@ -{"112":"Bonaire","149":"Hungary","211":"Brazil","163":"Liechtenstein","105":"Puerto Rico","170":"England","17":"Côte d'Ivoire","71":"Hong Kong","156":"Russia","48":"Malawi","113":"Guadeloupe","148":"Czech Republic","210":"Argentina","162":"Bosnia-Herzegovina","104":"Montserrat","171":"Scotland","16":"Burkina Faso","70":"China","157":"Turkey","49":"Mozambique","28":"Gabon","110":"Turks and Caicos Islands","213":"Paraguay","59":"Bangladesh","161":"Iceland","198":"Fiji","107":"Saint Lucia","172":"Wales","15":"Benin","73":"North Korea","154":"Croatia","29":"São Tomé and Príncipe","111":"United States Virgin Islands","212":"Chile","58":"Afghanistan","160":"Norway","199":"New Caledonia","106":"Saint Kitts and Nevis","173":"Northern Ireland","14":"Sierra Leone","72":"Japan","155":"Serbia","8":"Guinea","116":"Sint Maarten","88":"Vietnam","215":"Colombia","189":"Yemen","167":"Georgia","101":"Grenada","174":"Faroe Islands","13":"Senegal","75":"Macau","138":"Portugal","152":"Belarus","39":"Tanzania","9":"Guinea-Bissau","117":"Honduras","89":"Anguilla","214":"Uruguay","188":"United Arab Emirates","166":"San Marino","100":"Dominican Republic","175":"Gibraltar","12":"Mauritania","74":"South Korea","139":"Slovakia","153":"Switzerland","38":"Sudan","114":"Martinique","99":"Dominica","217":"Peru","165":"Moldova","103":"Jamaica","176":"Israel","208":"Niue","11":"Mali","77":"Taiwan","129":"Spain","68":"Turkmenistan","150":"Andorra","115":"Saint Martin","98":"Curaçao","216":"Ecuador","164":"Montenegro","102":"Haiti","177":"Bahrain","209":"Tuvalu","10":"Liberia","76":"Mongolia","128":"Estonia","69":"Uzbekistan","151":"Albania","22":"Cameroon","4":"Libya","97":"Cuba","84":"Philippines","141":"Bulgaria","219":"Bolivia","53":"Swaziland","185":"Qatar","192":"Canada","178":"Iran","206":"Vanuatu","220":"Guyana","79":"Cambodia","127":"Germany","134":"Italy","66":"Sri Lanka","35":"Rwanda","40":"Uganda","23":"Central African Republic","5":"Tunisia","96":"Cayman Islands","85":"Singapore","140":"Slovenia","218":"Venezuela","52":"South Africa","184":"Palestine","193":"Australia","179":"Iraq","207":"Kiribati","221":"Suriname","78":"Brunei","126":"Cyprus","135":"Luxembourg","67":"Tajikistan","34":"Kenya","41":"Zanzibar","20":"Nigeria","6":"Cape Verde","118":"Costa Rica","95":"British Virgin Islands","86":"Thailand","143":"Latvija","51":"Seychelles","187":"Syria","169":"Azerbaijan","190":"Mexico","204":"Tahiti","222":"French Guiana","125":"Belgium","136":"Malta","64":"Nepal","37":"South Sudan","42":"Angola","21":"Togo","7":"Gambia","119":"El Salvador","94":"Bermuda","87":"Timor-Leste","142":"Denmark","50":"Namibia","186":"Saudi Arabia","168":"Armenia","191":"United States","205":"Tonga","124":"Austria","137":"Netherlands","65":"Pakistan","36":"Somalia","43":"Botswana","26":"Congo DR","93":"Barbados","80":"Indonesia","145":"Poland","57":"Kazakhstan","181":"Kuwait","196":"American Samoa","109":"Trinidad and Tobago","202":"Samoa","123":"Nicaragua","130":"Finland","62":"Kyrgyzstan","31":"Djibouti","44":"Comoros","27":"Equatorial Guinea","1":"Algeria","92":"Bahamas","81":"Laos","144":"Lithuania","56":"Réunion","180":"Jordan","197":"Cook Islands","108":"Saint Vincent and the Grenadines","203":"Solomon Islands","122":"Belize","131":"France","63":"Maldives","30":"Burundi","45":"Lesotho","24":"Chad","2":"Egypt","91":"Aruba","82":"Malaysia","147":"Sweden","55":"Zimbabwe","183":"Oman","194":"Guam","200":"New Zealand","19":"Niger","121":"Guatemala","132":"Greece","60":"Bhutan","158":"Ukraine","33":"Ethiopia","46":"Mauritius","25":"Congo","3":"Morocco","90":"Antigua and Barbuda","83":"Myanmar","146":"Romania","54":"Zambia","182":"Lebanon","195":"Northern Mariana Islands","201":"Papua New Guinea","18":"Ghana","120":"Panama","133":"Ireland","61":"India","159":"Macedonia","32":"Eritrea","47":"Madagascar"} \ No newline at end of file +[{"g":3,"ct":"Nigeria","cn":"Africa","id":20},{"g":4,"ct":"Côte d'Ivoire","cn":"Africa","id":17},{"g":1,"ct":"Cameroon","cn":"Africa","id":22},{"g":4,"ct":"Ghana","cn":"Africa","id":18},{"g":7,"ct":"Algeria","cn":"Africa","id":1},{"g":3,"ct":"Australia","cn":"Pacific","id":193},{"g":1,"ct":"Iran","cn":"Middle East","id":178},{"g":2,"ct":"Japan","cn":"Asia","id":72},{"g":3,"ct":"South Korea","cn":"Asia","id":74},{"g":13,"ct":"Costa Rica","cn":"Central America","id":118},{"g":5,"ct":"United States","cn":"North America","id":191},{"g":1,"ct":"Honduras","cn":"Central America","id":117},{"g":5,"ct":"México","cn":"North America","id":190},{"g":14,"ct":"Brazil","cn":"South America","id":211},{"g":12,"ct":"Argentina","cn":"South America","id":210},{"g":12,"ct":"Colombia","cn":"South America","id":215},{"g":8,"ct":"Chile","cn":"South America","id":212},{"g":3,"ct":"Ecuador","cn":"South America","id":216},{"g":4,"ct":"Uruguay","cn":"South America","id":214},{"g":6,"ct":"Belgium","cn":"Europe","id":125},{"g":18,"ct":"Germany","cn":"Europe","id":127},{"g":2,"ct":"Italy","cn":"Europe","id":134},{"g":21,"ct":"Netherlands","cn":"Europe","id":137},{"g":7,"ct":"Switzerland","cn":"Europe","id":153},{"g":4,"ct":"Bosnia and Herzegovina","cn":"Europe","id":162},{"g":2,"ct":"Russia","cn":"Europe","id":156},{"g":4,"ct":"Spain","cn":"Europe","id":129},{"g":2,"ct":"England","cn":"Europe","id":170},{"g":6,"ct":"Greece","cn":"Europe","id":132},{"g":6,"ct":"Croatia","cn":"Europe","id":154},{"g":4,"ct":"Portugal","cn":"Europe","id":138},{"g":10,"ct":"France","cn":"Europe","id":131}] \ No newline at end of file