On Wed, Aug 5, 2009 at 08:05, John Harrop<jharrop...@gmail.com> wrote: > I just saw someone post a bunch of Clojure code to comp.lang.lisp one > function from which was: > (defn partition-with [pred coll] > (loop [in coll curr [] out []] > (if (empty? in) > (conj out curr) > (let [obj (first in)] > (if (pred obj) > (recur (rest in) [] (conj out curr)) > (recur (rest in) (conj curr obj) out)))))) > This looks like it might be generally useful (and the CLL poster thought so > too); it splits a collection at items determined by the predicate, producing > a vector of vectors of items not matching the predicate: > user=> (partition-with odd? [3 4 8 7 9 2 4 6]) > [[] [4 8] [] [2 4 6]] > (The empty collections are from before 3 and between 7 and 9, from the look > of it. > user=> (remove empty? (partition-with odd? [3 4 8 7 9 2 4 6])) > ([4 8] [2 4 6]) > gives what you might want instead, in some situations.) > > The same CLL poster noticed that conj with two maps for arguments seems to > duplicate the functionality of merge. I've just tested this and it seems to > be true, even with key duplications: > user=> (merge {:key2 2 :key3 3} {:key1 1 :key4 4 :key3 7} ) > {:key4 4, :key1 1, :key2 2, :key3 7} > user=> (conj {:key2 2 :key3 3} {:key1 1 :key4 4 :key3 7} ) > {:key4 4, :key1 1, :key2 2, :key3 7} > This makes merge appear redundant. > Further experimentation shows that there isn't even a type-safety reason to > prefer merge. It doesn't throw on vectors. In fact: > user=> (merge [1 2 3] 4) > [1 2 3 4] > user=> (merge '(1 2 3) 4) > (4 1 2 3) > user=> (merge #{1 2 3} 8) > #{1 2 3 8} > user=> (merge #{1 2 3} 3) > #{1 2 3} > user=> (merge #{1 2 3} #{4 3}) > #{1 2 3 #{3 4}} > user=> (conj #{1 2 3} #{4 3}) > #{1 2 3 #{3 4}} > so merge appears to be strictly synonymous with conj. Curiouser and > curiouser...
At first, I figured it'd be (defn merge "Returns a map that consists of the rest of the maps conj-ed onto the first. If a key occurs in more than one map, the mapping from the latter (left-to-right) will be the mapping in the result." [& maps] (when (some identity maps) (reduce #(conj (or %1 {}) %2) maps))) Merge combines (by reducing with conj) the maps its given. The difference is in how nil as the first argument is handled. When the first argument is nil, it is treated as if it were an empty map. (clojure has a somewhat ambiguous relation to nil. Often nil is treated as an empty collection, in this case en empty map. In contrast to regular empty collections, however, nil is considered false when evaluated as a boolean.) user> (merge {} {1 1.0} {2 2.0 3 3.0}) {3 3.0, 2 2.0, 1 1.0} user> (merge nil {1 1.0} {2 2.0 3 3.0}) {3 3.0, 2 2.0, 1 1.0} The other differences stem from the fact that conj works a little differently with maps than it does with lists and the fact that conj considers nil equivalent to empty list (unlike merge, which considers it equivalent to empty map). user> (conj nil {1 1.0} {2 2.0 3 3.0}) ({2 2.0, 3 3.0} {1 1.0}) user> (conj {} {1 1.0} {2 2.0 3 3.0}) {3 3.0, 2 2.0, 1 1.0} Here we also notice that conj supports more than two arguments, which makes me wonder why merge uses reduce in the first place. It would seem to be unnecessary. (defn my-merge [& maps] ;; this appears equivalent to clojure.core/merge (when (some identity maps) (apply conj (cons (or (first maps) {}) (rest maps))))) // ben --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---