Search code examples
functional-programmingclojure

How to convert a vector to a map according to this rule?


SOLVED BY SELF

(defn parse-args
  ([args]
   (parse-args args {}))
  ([[fst sec & more] rst]
   (let [value? (fn [x] (and (not (keyword? x))
                             (not (map? x))))]
     (cond
       (and (keyword? fst)
            (keyword? sec)) (parse-args (cons sec more) (merge rst {fst true}))
       (and (keyword? fst)
            (value? sec)) (parse-args more (merge rst {fst sec}))
       :else rst
       ))))


*im new to clojure

for example there is a vec like below:

[:enchant :type "Fire Aspect" :level 123]

try to convert it to:

{:enchant true :type "Fire Aspect" :level 123}

note that the original vec has been somehow 'interleaved'
but not every key has its 'value' (like :enchant)
and i just want to find out those and treat them as a boolean value
with true as their default value


i've tried to use:

(defn parse-arg [args toggle-coll]
  (let [is-value? #(not (and (keyword? %)
                             (map? %1)))]
    (reduce (fn [k1 k2]
              (merge
                (cond
                  (and (keyword? k1)
                       (keyword? k2)) ({} {k1 true})
                  (and (keyword? k1)
                       (is-value? k2)) ({} {}) ; and soon i found this method is difficult and clumsy
                  (and (map? k1)
                       (is-value? k2)) ({} {})
                  (and (map? k1)
                       (keyword? k2)) ({} {})
                  ;; omitted)
                )
              )
            args)))


Solution

  • we can also process the input data by the windows of 2 items and insert true between two keywords:

    (defn parse-args [data]
      (->> (concat data [::end])
           (partition 2 1)
           (mapcat (fn [[a :as pair]] 
                     (if (every? keyword? pair)
                       [a true]
                       [a])))
           (apply hash-map)))
    

    the ::end kv is added to handle the dangling keyword in the end of the sequence, if any.

    user> (parse-args [:a :b 1 :c 10 :d])
    ;;=> {:c 10, :b 1, :d true, :a true}