Search code examples
clojuretuples

Clojure: How to obtain a specific value from a tuple


I've been building my own project in Clojure and I want to get the value from this tuple by searching the first two values and getting the third value.

I've searched around and I can't find a solution to the problem, I want to build a function that will ask for two the first two values in each specific vector so it will come up with the third.

Here's the tuple so far.

(def cars
'#{[has car wheels]
   [has car radio]
   [has vauxhall suspension]
   [colour vauxhall red]
   [colour ford blue]
   [is vauxhall car]
   [is ford car]})

So for example, if I built a function called "search" and put in the first two values of the vector it would be like this

user   => (search 'has 'vauxhall)
answer => suspension

because that vector in the tuple is [has vauxhall suspension]

I'm just curious if there is any way to do this? Because I can't find any process online, but I want to build a function that does it (like the search function that I brought up for example), instead of any REPL shortcuts that will get me the answer.

I would appreciate any help or input :)


Solution

  • This is one way to do it.

    (def cars
      #{[:has :car :wheels]
        [:has :car :radio]
        [:has :vauxhall :suspension]
        [:colour :vauxhall :red]
        [:colour :ford :blue]
        [:is :vauxhall :car]
        [:is :ford :car]})
    
    (defn search [word1 word2]
      (some (fn [[w1 w2 w3]]
              (and (= word1 w1) (= word2 w2) w3)
            cars))
    
    (search :has :vauxhall)
    ;; =>:suspension
    

    Note I encoded the elements as keywords instead of symbols - keywords evaluate to themselves.

    The search function uses some that

    Returns the first logical true value of (pred x) for any x in coll, else nil.

    and returns the last argument if all arguments are true. In this case that's the requested element.

    This only returns the first hit, if you want them all you can use reduce:

    (defn search [word1 word2]
      (reduce
       (fn [acc [w1 w2 w3]]
         (if (and (= word1 w1) (= word2 w2))
           (conj acc w3)
           acc))
       #{}
       cars))
    
    (search :has :car)
    ;; => #{:radio :wheels}