beoliver
beoliver

Reputation: 5759

recursively following values in a hash map clojure

I have a problem providing an edge case for the following recursive function that searches hash maps and other similar key,value storage.

(def hashbrownies
  {"Mary","Dave"
   "Dave","Anne"
   "Anne","Tim"})

current approach

(defn recursive-lookup
  [key-lst search-func conditional]
  (let [next-key (search-func (first key-lst))]
    (if (conditional next-key)
      (reverse key-lst)
      (recur (cons next-key key-lst) search-func conditional))))

examples that are working

>> (recursive-lookup ["Mary"] #(hashbrownies %) (partial = nil))
=> ("Mary" "Dave" "Anne" "Tim")

>> (recursive-lookup ["Mary"] #(hashbrownies %) #(< (.length %) 4))
=> ("Mary" "Dave" "Anne")

Problematic:

>> (recursive-lookup ["Mary"] #(hashbrownies %) #(> (.length %) 4))
=> NullPointerException   clojure.lang.Reflector.invokeNoArgInstanceMember (Reflector.java:296)

I can see what the problem is: as the condition can not be met, the function #(> (.length %) 4) takes nil (the last possible return value) as an argument. But being new to Clojure I am not sure how to cover for this. Is there an idiomatic way?

solution:

(defn recursive-lookup
  [key-lst search-func conditional]
  (let [next-key (search-func (first key-lst))]
    (if (or (nil? next-key)
            (conditional next-key))
      (reverse key-lst)
      (recur (cons next-key key-lst) search-func conditional))))

Upvotes: 2

Views: 1214

Answers (1)

Mikita Belahlazau
Mikita Belahlazau

Reputation: 15434

You need to handle nil in your conditional function. You can use fnil for that. fnil replaces nil with some default value. So you can try:

(fnil #(> (.length %) 4) "")

If this conditional function receives nil it replaces nil with empty string "" and then call your function #(> (.length %) 4).

Also you can use count instead .length. Count returns 0 for nil:

(count "123") => 3
(count nil) => 0

Upvotes: 2

Related Questions