Search code examples
functional-programmingclojuredata-mining

I am trying to create an accumulator function for an vector of sets. But I keep getting strange results


Basically, I have a vector of sets. I'd like to merge the sets based on a criteria (you can see this criteria in the if statement). More than two sets may be merged. Here is an example data set:

[{:name "corner", :matched-shape "corner", :direction :e, :rotation 1}
                                        {:name "corner", :matched-shape "corner", :direction :e, :rotation 2}
                                        {:name "corner", :matched-shape "corner", :direction :s, :rotation 2}
                                        {:name "corner", :matched-shape "corner", :direction :s, :rotation 3}
                                        {:name "corner", :matched-shape "pipe", :direction :s, :rotation 0}
                                        {:name "corner", :matched-shape "pipe", :direction :e, :rotation 1}
                                        {:name "corner", :matched-shape "pipe", :direction :s, :rotation 2}
                                        {:name "corner", :matched-shape "pipe", :direction :e, :rotation 3}
                                        {:name "corner", :matched-shape "cross", :direction :e, :rotation 0}
                                        {:name "corner", :matched-shape "cross", :direction :s, :rotation 0}
                                        {:name "corner", :matched-shape "cross", :direction :e, :rotation 1}
                                        {:name "corner", :matched-shape "cross", :direction :s, :rotation 1}]

I have tried dozens of solutions but none of them work. Here is my code:

(defn merge-symmetry-table [symmetry-table]
  (filter #(if-not (nil? %) %) 
          (loop [[x y & remaining] symmetry-table result []]
            (if-not (empty? y)
              (if (and (= (:name x) (:name y))
                       (= (:direction x) (:direction y)))
                (recur [(concat-symmetries x y) remaining] result)
                (recur [conj y remaining] [result x]))
              (conj result x)))))

and my output as of now:

([]
 {:name "corner", :direction :e, :matched-shapes ["corner" 1 "corner" 2]}
 {:name nil, :direction nil, :matched-shapes [[nil nil nil nil] nil nil]})

I'm sure there is a nicer way to do this, but I would like to know what is exactly wrong with my code. I've gone it over literally fifty times and I cannot understand what is wrong. Thank you for your help.

I'm not sure if I am allowed to express dissatisfaction here (and I do not wish to bother anyone), but I have had absolutely immense difficulty dealing with data in this programming language. Admittedly, this is my first project in this language and I'm mostly a self-taught coder. But nesting vectors inside vectors and using just "keymaps" has made it an absolute nightmare trying to get anything done let alone organize data in a cohesive manner. I probably rewrite my functions at least ten times just to get them to return what I want. There must be something I'm missing.


Solution

  • You probably want to use either partition-by:

    (defn merge-symmetry-table [data]
      (->> data
           (partition-by (juxt :name :direction))
           (map (partial apply concat-symmetries))))
    

    or group-by:

    (defn merge-symmetry-table [data]
      (->> data
           (group-by (juxt :name :direction))
           vals
           (map (partial apply concat-symmetries))))