Search code examples
clojurefunctional-programming

Clojure manually find nth element in a sequence


I am a newbie to clojure (and functional programming for that matter) and I was trying to do some basic problems. I was trying to find the nth element in a sequence without recursion.

so something like

(my-nth '(1 2 3 4) 2) => 3

I had a hard time looping through the list and returning when i found the nth element. I tried a bunch of different ways and the code that I ended up with is

(defn sdsu-nth
 [input-list n]
 (loop [cnt n tmp-list input-list]
    (if (zero? cnt)
       (first tmp-list)
       (recur (dec cnt) (pop tmp-list)))))

This gives me an exception which says "cant pop from empty list"

I dont need code, but if someone could point me in the right direction it would really help!


Solution

  • You are using the function pop, which has different behavior for different data structures.

    user> (pop '(0 1 2 3 4))
    (1 2 3 4)
    user> (pop [0 1 2 3 4])
    [0 1 2 3]
    user> (pop (map identity '(0 1 2 3 4)))
    ClassCastException clojure.lang.LazySeq cannot be cast to clojure.lang.IPersistentStack  clojure.lang.RT.pop (RT.java:640)
    

    Furthermore, you are mixing calls to pop with calls to first. If iterating, use peek/pop or first/rest as pairs, mixing the two can lead to unexpected results. first / rest are the lowest common denominator, if you want to generalize over various sequential types, use those, and they will coerce the sequence to work if they can.

    user> (first "hello")
    \h
    user> (first #{0 1 2 3 4})
    0
    user> (first {:a 0 :b 1 :c 2})
    [:c 2]
    

    With your function, replacing pop with rest, we get the expected results:

    user> (defn sdsu-nth
            [input-list n]
            (loop [cnt n tmp-list input-list]
                  (if (zero? cnt)
                      (first tmp-list)
                    (recur (dec cnt) (rest tmp-list)))))
    
    #'user/sdsu-nth
    user> (sdsu-nth (map identity '(0 1 2 3 4)) 2)
    2
    user> (sdsu-nth [0 1 2 3 4] 2)
    2
    user> (sdsu-nth '(0 1 2 3 4) 2)
    2
    user> (sdsu-nth "01234" 2)
    \2