utilities — cgrand, 29 April 2009 @ 20 h 37 min

I recently learnt that when you want to convert the case of a technical identifier (a tagname, a HTTP header etc.) you must not use plain .toUpperCase or .toLowerCase but specify Locale/ENGLISH.

Counting occurences (solution to the exercise)

unsorted — cgrand, 28 April 2009 @ 18 h 00 min
What does (merge-with + {:a 12} {:b 4} {:a 3 :b 7}) return?
{:b 11, :a 15} when there are several values for a key, these values are merged (two at a time) using the specified function — here they are summed.
Can you count occurrences of each value in a collection using merge-with?
(apply merge-with + (map (fn [x] {x 1}) coll)) or, using for: (apply merge-with + (for [x coll] {x 1})).

Screenscraping with Enlive

enlive — cgrand, 27 April 2009 @ 19 h 02 min

(select (html-resource (java.net.URL. "http://clojure-log.n01se.net/")) [:#main [:a (attr? :href)]]) returns a seq of link nodes.

Counting occurences

unsorted — cgrand, @ 17 h 44 min

One asked me how to count occurrences of each value in a collection. I answered (reduce #(assoc %1 %2 (inc (%1 %2 0))) {} coll). Since it can take some time to get accustomed to the functional way of thought, here is how one can work such an expression out:

How to count all occurrences of 42?
(count (filter #{42} coll))
How to express count using reduce?
(defn my-count [coll] (reduce (fn [n _] (inc n)) 0 coll))
How to count all occurrences of 42 using reduce?
(reduce (fn [n _] (inc n)) 0 (filter #{42} coll))
Can you get rid of the filter?
(reduce (fn [n x] (if (= 42 x) (inc n) n)) 0 coll)
I’d like the result to be {42 occurences-count}.
(reduce (fn [m x] (if (= 42 x) (assoc m 42 (inc (m 42))) m)) {42 0} coll)
42 is hardcoded in four places, it’s bad!
(reduce (fn [m x] (if (= 42 x) (assoc m x (inc (m x))) m)) {42 0} coll)
Can’t you replace {42 0} with {}?
No (inc (m x)) would fail because (m x) would return nil.
How does one provide a default value when the key is not found ?
(a-map a-key default-value)
Can’t you replace {42 0} with {}?
(reduce (fn [m x] (if (= 42 x) (assoc m x (inc (m x 0))) m)) {} coll)
I changed my mind I’d like you to count occurrences of each value.
Easy! (reduce (fn [m x] (assoc m x (inc (m x 0)))) {} coll) or, terser, (reduce #(assoc %1 %2 (inc (%1 %2 0))) {} coll)


What does (merge-with + {:a 12} {:b 4} {:a 3 :b 7}) return?
Can you count occurrences of each value in a collection using merge-with?

Vicious bug

mistakes — cgrand, 22 April 2009 @ 11 h 44 min
What’s wrong with this code (do (defmacro foobar [x] (doto x println)) (foobar (+ 1 1)))?
Run it again.
The first time, foobar is treated as a function (its argument has been evaluated) because foobar is unknown before the whole top-level expression is compiled.
The second time, the var named foobar preexists and is a macro, (foobar (+ 1 1)) is expanded.

This behaviour bit me while using with-test to test macros. It’s the kind of bug that goes unnoticed while developing incrementally and evaluating in the same REPL, it was waiting for me to start a fresh REPL.

Sanitizing HTML with Enlive

enlive — cgrand, @ 11 h 35 min
net.cgrand.enlive-html=> (sniptest "<div id=user-data>" 
  [:#user-data] (html-content "code injection<script>alert('boo')</script>") 
  [:#user-data (but #{:p :br :a :strong :em})] nil)
"<html><body><div id=\"user-data\">code injection</div></body></html>"

You also need to remove most attributes but it’s just a demo of something that was impossible with the old Enlive.

By the way, the old Enlive is no more. Long live the new Enlive!

Make it work, make it right, make it fast

enlive — cgrand, 18 April 2009 @ 9 h 33 min

Make it work, make it right, make it fast.

Make it work
sort of done: the old Enlive,
Make it right
work in progress, the new Enlive,
Make it fast
once the “right” branch is merged into master.

See the README file to know what’s new and here for an example.

Mapping every second item

utilities — cgrand, 17 April 2009 @ 10 h 58 min

I wanted to apply a function to every second item in a coll. I was considering writing something using interleave, take-nth and map or a combination of mapcat and partition when I thought of this:

(map #(%1 %2) (cycle [f identity]) coll)

I really love clojure’s map parallel processing. (I should ask if every? and some could be allowed to take several colls.)

(c) 2023 Clojure and me | powered by WordPress with Barecity