dirtymikeandtheboys
dirtymikeandtheboys

Reputation: 541

Clojure opposite of reduce?

I run into this problem a lot (more often in clojurescript) but haven't noticed how others deal with it. This is what I want:

[:div.container [:div.first "first"] [:div.second "second"] [:div.third "third"]]

And let's say I'm building it from a collection like: ["first" "second" "third"]

I'll pass the collection through a mapv and wind up with (this code is a sketch, I'm not using it):

(mapv
  #([(keyword (str "div." %)) %])
  ["first" "second" "third"])
=> [[:div.first "first"] [:div.second "second"] [:div.third "third"]]

And if I were to use it inside the container div, I'd get:

[:div.container [[:div.first "first"] [:div.second "second"] [:div.third "third"]]]

I've been using things like cons to put the :div.container at the front of the result of mapv. But in my mind there should be a better way--like an opposite of reduce. Is there such a thing?

Edit: I did find concat and it looks like I've tried it before, but I get a sequence back. I want a vector. (vec (concat ... )) is not ideal.

Upvotes: 0

Views: 442

Answers (4)

user2946753
user2946753

Reputation: 41

Are you aware that [:ul ([:li "one"] [:li "two"])] will work as expected?

I think if you change (mapv f coll) to

(map f coll)

or

(doall (map f coll))

You'll get the result you're looking for.

Upvotes: 0

noisesmith
noisesmith

Reputation: 20194

The "opposite of reduce" is reduce.

(reduce (fn [v s]
          (conj v [(keyword (str "div." s)) s]))
        [:div.container]
        ["first" "second" "third"])

Upvotes: 1

user2524973
user2524973

Reputation: 1107

cons is fine here -- it's been around since the dawn of Lisp and it's useful for exactly what you want to do here.

Here's how I'd approach this:

(defn containerize
  [tag v]
  (let [kw #(keyword (str tag "." %))]
    (into [] 
      (cons (kw "container")
        (map (fn [x] [(kw x) x]) v)))))

Upvotes: 1

danidiaz
danidiaz

Reputation: 27756

How about:

 (apply vector :div.container 
               (mapv #(vector (keyword (str "div." %)) %) 
                     ["first", "second", "third"]))

The idea is to use apply to pass each element of the result of mapv as an individual argument to vector.

As a bonus, apply admits other arguments before the collection argument, so we can stow the :div.container there.

(Here using mapv vs. map would be indifferent.)

(Also, the "opposite" of reduce is usually called unfold in other languages, but I havent found the analogous function in the core Clojure libraries.)

Upvotes: 4

Related Questions