#lang typed/racket/base
(require typed/json)
#|
Calculate the maximum depth of a JSON object read from input
Algorithm:
1. Read user input and parse JSON.
2. If input has no data, return 0.
2. Begin `max-depth` with the parsed JSON data and depth of 0.
a. If the JSON input is a list, loop over each element of the list and pass
the element as an input for `max-depth` and increment the depth. Repeat step 2.
b. If the JSON input is a hash table, use each values of the table as the input list
for step 2.a.
c. If the JSON input is a number, string, boolean, or null, return the depth.
3. Print the maximum depth.
|#
(: max-depth (-> JSExpr Real Real))
(define (max-depth input depth)
(let ([depth+1 (+ depth 1)])
(cond [(list? input)
(apply max
(cons depth+1
(map (λ ([elem : JSExpr]) : Real
(max-depth elem depth+1))
input)))]
[(hash? input)
(apply max
(cons depth+1
(hash-map input
(λ ([_ : Symbol] [value : JSExpr]) : Real
(max-depth value depth+1)))))]
[else depth])))
(: main (-> (U JSExpr EOF) Real))
(define (main input)
(cond [(equal? eof input) 0]
[else (max-depth input 0)]))
(displayln (main (read-json)))
#| Tests [Remove line to run after input, if all pass, nothing will display.]
(require (only-in typed/rackunit check-equal?))
(check-equal? (main (string->jsexpr "[]")) 1)
(check-equal? (main (string->jsexpr "[1, 2, 3, 4, 5]")) 1)
(check-equal? (main (string->jsexpr "[ [ 123], []]")) 2)
(check-equal? (main (string->jsexpr "[{\"a\": []}, [\"abc\"]]")) 3)
(check-equal? (main (string->jsexpr "{\"a\": 321}")) 1)
(check-equal? (main (string->jsexpr "{\"a\": []}")) 2)
(check-equal? (main (string->jsexpr "\"hello\"")) 0)
(check-equal? (main (string->jsexpr "[\"abc[]bca\"]")) 1)
Tests [Remove line to run after input, if all pass, nothing will display.] |#
Compilation
Once Racket is installed one your system, simply run:
raco exe /path/to/this_file.rkt
Best compiled without the tests.
Explanation
Racket provides a nice built-in package called json
that parses JSON expressions (JSExpr
). All lists in the JSON expression are parsed into Racket Lists and all dictionaries are parsed into Hash Tables where the keys are Symbols and the values are other JSExpr
s. The reason I am using Typed Racket is that it is potentially faster than the dynamically typed language.
Conclusion
This is my submission for the challenge, I am not that great at optimizing code, so I don't expect peak performance in its runs. I did do a sample test on my machine with a 64kB minified JSON file which ran (according to time
) at about 700ms. As a note though, my CPU is Intel 2 Duo E8500 and 2GB RAM, so I think it should be faster on other machines :)
Have an amazing weekend!
hello
is invalid on purpose, however"hello"
should also return a depth of 0 \$\endgroup\$["\\\",[],\\\""]
→ 1,["\\\\",[],"\\\\"]
→ 2. Also, I assume you are generating large test cases to evaluate speed—in order to have an objective winning criterion, you need to share the details so that evaluation can be reproduced. \$\endgroup\$