Skip to content

Instantly share code, notes, and snippets.

@WalternativE
Created September 4, 2018 21:36
Show Gist options
  • Save WalternativE/61ce85bb8aa29027b8de93030997bfb3 to your computer and use it in GitHub Desktop.
Save WalternativE/61ce85bb8aa29027b8de93030997bfb3 to your computer and use it in GitHub Desktop.
A possible solution for the C4FS Type Provider Treasure Hunt Dojo
#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