'Calculating image of a Set in Clojure includes nil value?

 (defn image-of 
   "computes the image of the element x under R"
   [R x]
   (set 
     (for [r R] 
       (when (= (first r) x) 
         (second r)))))

Function idea: Add the second variable in R when it's first is equal to x.

So this function is supposed to compute image of a relation. This is kinda successful. When running a test I get this result:

Input: (image-of #{[1 :a] [2 :b] [1 :c] [3 :a]} 1)

Expected: #{:c :a}

Actual: #{nil :c :a}

So it includes a nil value for some reason. What in the function causes this? I guess I could filter out any nil values but would like to have the solution on a single line.



Solution 1:[1]

So the problem was I didn't know exactly how to use when This solution does it:

(set (for [r R 
           :when (= (first r) x)] 
       (second r)))

Solution 2:[2]

Let me suggest a different approach.

The natural way to represent a relation in Clojure is as a map from keys to sets (or other collections) of values. A function to convert your collection of pairs to this form is ...

(defn pairs->map [pairs]
  (reduce
    (fn [acc [key value]]
      (assoc acc key (conj (acc key #{}) value)))
    {}
    pairs))

For example, ...

(pairs->map #{[1 :a] [2 :b] [1 :c] [3 :a]})
=> {2 #{:b}, 1 #{:c :a}, 3 #{:a}}

You can use this map as a function. I you feed it a key, it returns the corresponding value:

({2 #{:b}, 1 #{:c :a}, 3 #{:a}} 1)
=> #{:c :a}

You construct this map once and or all and use it as often as you like. Looking it up as a function is effectively a constant-time operation. But you run through the entire collection of pairs every time you evaluate image-of.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Alan Thompson
Solution 2 Thumbnail