1
votes

I have a vector of maps like this one

  (def map1 
    [{:name "name1"
      :field "xxx"}
     {:name "name2"
      :requires {"element1" 1}}
     {:name "name3"
      :consumes {"element2" 1 "element3" 4}}])

I'm trying to define a functions that takes in a map like {"element1" 1 "element3" 6} (ie: with n fields, or {}) and fiters the maps in map1, returning only the ones that either have no requires and consumes, or have a lower number associated to them than the one associated with that key in the provided map (if the provided map doesn't have any key like that, it's not returned)

but I'm failing to grasp how to approach the maps recursive loop and filtering

(defn getV [node nodes]

  (defn filterType [type nodes]
    (filter (fn [x] (if (contains? x type)
                    false ; filter for key values here
                    true)) nodes))

  (filterType :requires (filterType :consumes nodes)))
1
hello davis! I edited the question to reflect exactly where I'm stuck with the codeSovos

1 Answers

2
votes

There's two ways to look at problems like this: from the outside in or from the inside out. Naming things carefully can really help when working with nested structures. For example, calling a vector of maps map1 may be adding to the confusion.

Starting from the outside, you need a predicate function for filtering the list. This function will take a map as a parameter and will be used by a filter function.

(defn comparisons [m]
   ...)

(filter comparisons map1)

I'm not sure I understand the comparisons precisely, but there seems to be at least two flavors. The first is looking for maps that do not have :requires or :consumes keys.

(defn no-requires-or-consumes [m]
   ...)

(defn all-keys-higher-than-values [m]
  ...)

(defn comparisons [m]
   (some #(% m) [no-requires-or-consumes all-keys-higher-than-values]))

Then it's a matter of defining the individual comparison functions

(defn no-requires-or-consumes [m]
   (and (not (:requires m)) (not (:consumes m))))

The second is more complicated. It operates on one or two inner maps but the behaviour is the same in both cases so the real implementation can be pushed down another level.

(defn all-keys-higher-than-values [m]
  (every? keys-higher-than-values [(:requires m) (:consumes m)]))

The crux of the comparison is looking at the number in the key part of the map vs the value. Pushing the details down a level gives:

(defn keys-higher-than-values [m]
  (every? #(>= (number-from-key %) (get m %)) (keys m)))

Note: I chose >= here so that the second entry in the sample data will pass.

That leaves only pulling the number of of key string. how to do that can be found at In Clojure how can I convert a String to a number?

(defn number-from-key [s]
    (read-string (re-find #"\d+" s)))

Stringing all these together and running against the example data returns the first and second entries.

Putting everything together:

(defn no-requires-or-consumes [m]
   (and (not (:requires m)) (not (:consumes m))))

(defn number-from-key [s]
   (read-string (re-find #"\d+" s)))

(defn all-keys-higher-than-values [m]
  (every? keys-higher-than-values [(:requires m) (:consumes m)]))

(defn keys-higher-than-values [m]
 (every? #(>= (number-from-key %) (get m %)) (keys m)))

(defn comparisons [m]
  (some #(% m) [no-requires-or-consumes all-keys-higher-than-values]))

(filter comparisons map1)