Skip to content

Instantly share code, notes, and snippets.

@Artiavis
Last active October 22, 2015 04:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Artiavis/29de21935d0afae782c4 to your computer and use it in GitHub Desktop.
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.
#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