Created
September 4, 2018 21:36
-
-
Save WalternativE/61ce85bb8aa29027b8de93030997bfb3 to your computer and use it in GitHub Desktop.
A possible solution for the C4FS Type Provider Treasure Hunt Dojo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#r "System.Xml.Linq.dll" | |
#r "packages/FSharp.Data/lib/net45/FSharp.Data.dll" | |
open FSharp.Data | |
// ------------------------------------------------------------------ | |
// WORD #1 | |
// | |
// Use the WorldBank type provider to get all countries in the | |
// "North America" region, then find country "c" with the smallest | |
// "Life expectancy at birth, total (years)" value in the year 2000 | |
// and return the first two letters of the "c.Code" property | |
// ------------------------------------------------------------------ | |
// Create connection to the WorldBank service | |
let wb = WorldBankData.GetDataContext() | |
// Get specific indicator for a specific country at a given year | |
wb.Countries.``Czech Republic``.Indicators.``Population ages 0-14 (% of total)``.[2000] | |
// Get a list of countries in a specified region | |
for c in wb.Regions.``Euro area``.Countries do | |
printfn "%s" c.Name | |
let wordOne = | |
wb.Regions.``North America``.Countries | |
|> Seq.minBy (fun c -> c.Indicators.``Life expectancy at birth, total (years)``.[2000]) | |
|> (fun c -> c.Code.Substring(0, 2)) | |
// ------------------------------------------------------------------ | |
// WORD #2 | |
// | |
// Read the RSS feed in "data/bbc.xml" using XmlProvider and return | |
// the last word of the title of an article that was published at | |
// 9:05am (the date does not matter, just hours & minutes) | |
// ------------------------------------------------------------------ | |
// Create a type for working with XML documents based on a sample file | |
type Sample = XmlProvider<"data/writers.xml"> | |
// Load the sample document - explore properties using "doc." | |
let doc = Sample.GetSample() | |
type RSS = XmlProvider<"data/bbc.xml"> | |
let rssFeed = RSS.GetSample() | |
let interestingItems = | |
rssFeed.Channel.Items | |
|> Seq.filter (fun item -> | |
let dt = item.PubDate | |
dt.Hour = 9 && dt.Minute = 5) | |
let wordTwo = | |
interestingItems | |
|> Seq.head | |
|> (fun item -> item.Title.Split(' ')) | |
|> Seq.last | |
// ------------------------------------------------------------------ | |
// WORD #3 | |
// | |
// Get the ID of a director whose name contains "Haugerud" and then | |
// search for all movie credits where he appears. Then return the | |
// second (last) word from the movie he directed in 2012 (the resulting | |
// type has properties "Credits" and "Crew" - you need movie from the | |
// Crew list. | |
// ------------------------------------------------------------------ | |
// Using The MovieDB REST API | |
// Make HTTP request to /3/search/person | |
let key = "17b987990a02ad7dbd3c881d0b75403f" | |
let name = "craig" | |
let data = | |
Http.RequestString | |
( "http://api.themoviedb.org/3/search/person", | |
query = [ ("query", name); ("api_key", key) ], | |
headers = [ HttpRequestHeaders.Accept HttpContentTypes.Json ] ) | |
// Parse result using JSON provider | |
// (using sample result to generate types) | |
type PersonSearch = JsonProvider<"data/personsearch.json"> | |
let sample = PersonSearch.Parse(data) | |
let first = sample.Results |> Seq.head | |
first.Name | |
// Request URL: "http://api.themoviedb.org/3/person/<id>/movie_credits | |
// (You can remove the 'query' parameter because it is not needed here; | |
// you need to put the director's ID in place of the <id> part of the URL) | |
// Use JsonProvider with sample file "data/moviecredits.json" to parse | |
let searchData = | |
Http.RequestString | |
( "http://api.themoviedb.org/3/search/person", | |
query = [ ("query", "Haugerud"); ("api_key", key) ], | |
headers = [ HttpRequestHeaders.Accept HttpContentTypes.Json ] ) | |
let directorSample = PersonSearch.Parse(searchData) | |
let firstEntry = Seq.head directorSample.Results | |
let creditsSearchData = | |
Http.RequestString | |
( sprintf "http://api.themoviedb.org/3/person/%i/movie_credits" firstEntry.Id, | |
query = [ ("api_key", key) ], | |
headers = [ HttpRequestHeaders.Accept HttpContentTypes.Json ] ) | |
type MovieCredits = JsonProvider<"data/moviecredits.json"> | |
let credits = MovieCredits.Parse(creditsSearchData) | |
let theMovieWeWant = | |
credits.Crew | |
|> Array.filter (fun f -> f.ReleaseDate.Year = 2012 && f.Job = "Director") | |
|> Array.head | |
let wordThree = theMovieWeWant.Title.Split(' ').[1] | |
// ------------------------------------------------------------------ | |
// WORD #4 | |
// | |
// Use CsvProvider to parse the file "data/librarycalls.csv" which | |
// contains information about some PHP library calls (got it from the | |
// internet :-)). Note that the file uses ; as the separator. | |
// | |
// Then find row where 'params' is equal to 2 and 'count' is equal to 1 | |
// and the 'name' column is longer than 6 characters. Return first such | |
// row and get the last word of the function name (which is separated | |
// by underscores). Make the word plural by adding 's' to the end. | |
// ------------------------------------------------------------------ | |
// Demo - using CSV provider to read CSV file with custom separator | |
type Lib = CsvProvider<"data/mortalityny.tsv", Separators="\t"> | |
// Read the sample file - explore the collection of rows in "lib.Rows" | |
let lib = Lib.GetSample() | |
type LibraryCalls = CsvProvider<"data/librarycalls.csv", Separators=";"> | |
let libraryCalls = LibraryCalls.GetSample() | |
let wordFour = | |
libraryCalls.Rows | |
|> Seq.filter (fun r -> r.Params = 2 && r.Count = 1 && r.Name.Length > 6) | |
|> Seq.head | |
|> (fun r -> r.Name.Split('_') |> Seq.last) | |
|> (fun w -> w + "s") | |
// NOTE: The librarycalls.csv file uses ';' as the separator! | |
// ------------------------------------------------------------------ | |
// WORD #5 | |
// | |
// In addition to XML, JSON and CSV, the F# Data library can also | |
// parse HTML tables! Use the HtmlProvider to read data from wiki | |
// page with chemical elements (or use local 'data/elements.html'): | |
// - http://en.wikipedia.org/wiki/List_of_elements | |
// | |
// Your task is to find chemical element with "Atomic number" equal | |
// to 36 (column 'Z' of the table) and then return the 3rd and 2nd | |
// letter from the *end* of its name (that is 5th and 6th letter | |
// from the start). | |
// ------------------------------------------------------------------ | |
// Use HtmlProvider with "data/elements.html" file as a sample | |
type Elements = HtmlProvider<"data/elements.html"> | |
let elements = Elements.Load("http://en.wikipedia.org/wiki/List_of_elements") | |
let wordFive = | |
elements.Tables.List.Rows | |
|> Seq.find (fun r -> r.Column1 = 36.0) | |
|> (fun el -> el.Column3.[4..5]) | |
// ------------------------------------------------------------------ | |
// WORD #6 | |
// | |
// Use CsvProvider to load the Titanic data set from "data/Titanic.csv" | |
// (using the default column separator) and find the name of a female | |
// passenger who was 19 years old and embarked in the port marked "Q" | |
// Then return Substring(19, 3) from her name. | |
// ------------------------------------------------------------------ | |
// Use CsvProvider with the "data/titanic.csv" file as a sample | |
type Titanic = CsvProvider<"data/titanic.csv"> | |
let titanic = Titanic.GetSample() | |
let wordSix = | |
titanic.Rows | |
|> Seq.filter (fun r -> r.Sex = "female" && r.Age = 19. && r.Embarked = "Q") | |
|> Seq.head | |
|> (fun p -> p.Name.Substring(19, 3)) | |
// ------------------------------------------------------------------ | |
// WORD #7 | |
// | |
// Using the same RSS feed as in Word #2 ("data/bbc.xml"), find | |
// item that contains "Duran Duran" in the title and return the | |
// 14th word from its description (split the description using ' ' | |
// as the separator and get item at index 13). | |
// ------------------------------------------------------------------ | |
// (...) | |
let wordSeven = | |
rssFeed.Channel.Items | |
|> Seq.find (fun i -> i.Title.Contains("Duran Duran")) | |
|> (fun i -> i.Description.Split(' ').[13]) | |
let theSentence = | |
sprintf "%s %s %s %s %s %s %s" wordTwo wordSeven wordFour wordSix wordThree wordFive wordOne |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment