Last active
October 22, 2015 04:24
-
-
Save Artiavis/29de21935d0afae782c4 to your computer and use it in GitHub Desktop.
A solution to the Reddit "Daily Programmer" Easy Challenge "JSON Treasure Hunt", found at https://www.reddit.com/r/dailyprogrammer/comments/3j3pvm/20150831_challenge_230_easy_json_treasure_hunt/. Also note a Clojure solution at https://gist.github.com/Artiavis/017b42017a3275cbbfe8.
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 "FSharp.Data.dll" | |
open System | |
open System.IO | |
open FSharp.Data | |
type TreasurePathCrumb = | |
| Index of int | |
| Key of string | |
type HuntResult = | |
| Null | |
| TreasurePath of TreasurePathCrumb list | |
let buildTreasurePathString (path:TreasurePathCrumb list) = | |
let crumbToString crumb = | |
match crumb with | |
| TreasurePathCrumb.Index i -> string i | |
| TreasurePathCrumb.Key k -> k | |
let stringCrumbs = List.map crumbToString path | |
stringCrumbs |> String.concat " -> " | |
let rec findMapTreasure (json:(string * JsonValue) list) = | |
match json with | |
| [] -> HuntResult.Null | |
| (key, value) :: rest -> | |
match findTreasure value with | |
| HuntResult.Null -> findMapTreasure rest | |
| HuntResult.TreasurePath (path) -> HuntResult.TreasurePath (TreasurePathCrumb.Key(key)::path) | |
and findListTreasure (list:JsonValue list) (index:int) = | |
match list with | |
| [] -> HuntResult.Null | |
| first :: rest -> | |
match findTreasure first with | |
| HuntResult.Null -> findListTreasure rest (1 + index) | |
| HuntResult.TreasurePath (path) -> HuntResult.TreasurePath (TreasurePathCrumb.Index(index)::path) | |
and findTreasure (json:JsonValue) = | |
match json with | |
| JsonValue.Null -> HuntResult.Null | |
| JsonValue.Boolean b -> HuntResult.Null | |
| JsonValue.Float f -> HuntResult.Null | |
| JsonValue.Number n -> HuntResult.Null | |
| JsonValue.String s -> | |
if s = "dailyprogrammer" then HuntResult.TreasurePath([]) | |
else HuntResult.Null | |
| JsonValue.Array a -> findListTreasure (Array.toList a) 0 | |
| JsonValue.Record map -> findMapTreasure (Array.toList map) | |
let jsonTreasureHunt jsonRoot = | |
let huntResults = findTreasure jsonRoot | |
match huntResults with | |
| HuntResult.Null -> "We came back empty handed!" | |
| HuntResult.TreasurePath path -> buildTreasurePathString path | |
let startTheHunt jsonFile = | |
try | |
let stopWatch = System.Diagnostics.Stopwatch.StartNew() | |
let jsonFileReader = new StreamReader(jsonFile:string) | |
let jsonRoot = JsonValue.Load(jsonFileReader) | |
let huntResultCry = jsonTreasureHunt jsonRoot | |
stopWatch.Stop() | |
printfn "%s" huntResultCry | |
printfn "Total Time Taken: %f ms" stopWatch.Elapsed.TotalMilliseconds | |
with | |
| :? ArgumentNullException -> printfn "File path %A was null!" jsonFile | |
| :? ArgumentException -> printfn "Path was \"%A\" an empty string!" jsonFile | |
| :? FileNotFoundException -> printfn "File \"%A\" could not be found!" jsonFile | |
| :? DirectoryNotFoundException -> printfn "The path \"%A\" was invalid, could not find directory!" jsonFile | |
| :? IOException -> printfn "Syntax for path was invalid!" | |
let args = fsi.CommandLineArgs | |
match fsi.CommandLineArgs with | |
| [| scripName; jsonFile |] -> | |
startTheHunt jsonFile |> ignore | |
| _ -> | |
printfn "USAGE: [json-treasure-file]" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment