tags:

views:

95

answers:

4

Hi, I am a beginner in Clojure, and I have a simple question

Lets say i have a List, composed of Maps. Each Map has a :name and :age

My code is:

(def Person {:nom rob :age 31 } ) (def Persontwo {:nom sam :age 80 } ) (def Persontthree {:nom jim :age 21 } ) (def mylist (list Person Persontwo Personthree))

Now how do i traverse the list. Let's say for example, that i have a given :name. How do i traverse the list to see if any of the Maps :name matches my :name. And then if there is a map that matches, how do i get the index position of that map?

-Thank you

+1  A: 
(defn find-person-by-name [name people] 
   (let
      [person (first (filter (fn [person] (= (get person :nom) name)) people))]
      (print (get person :nom))
      (print (get person :age))))

EDIT: the above was the answer to the question as it was before question was edited; here's the updated one - filter and map were starting to get messy, so I rewrote it from scratch using loop:

; returns 0-based index of item with matching name, or nil if no such item found
(defn person-index-by-name [name people] 
    (loop [i 0 [p & rest] people]
        (cond
            (nil? p)
                nil
            (= (get p :nom) name) 
                i
            :else
                (recur (inc i) rest))))
Pavel Minaev
wow, Thank you so much. I knew i had to do it with filter, however i wasn't exactly sure of the syntax. Thanks once again
+1  A: 

This can be done with doseq:

(defn print-person [name people]
  (doseq [person people]
    (when (= (:nom person) name)
      (println name (:age person)))))
Jonas
I may be wrong (I had to actually go read the Clojure intro to produce the answer above), but isn't this going to iterate the whole sequence printing out all matching elements, and not just the first one? And if the sequence is guaranteed to only have one matching element, wouldn't it consequently unnecessarily keep iterating the rest of it?
Pavel Minaev
yes, that is correct. I thought that was the question. Perhaps I misinterpreted.
Jonas
But the question has changed now, so I guess it doesn't matter :-)
Jonas
+1  A: 

I would suggest looking at the filter function. This will return a sequence of items that match some predicate. As long as you don't have name duplication (and your algorithm would seem to dictate this), it would work.

Steve Rowe
A: 

Since you changed your question I give you a new answer. (I don't want to edit my old answer since that would make the comments very confusing).

There might be a better way to do this...

(defn first-index-of [key val xs]
  (loop [index 0
         xs xs]
    (when (seq xs)
      (if (= (key (first xs)) val)
        index
        (recur (+ index 1)
               (next xs))))))

This function is used like this:

> (first-index-of :nom 'sam mylist)
1
> (first-index-of :age 12 mylist)
nil
> (first-index-of :age 21 mylist)
2
Jonas