Simple comparator does not sort as (I) expected - clojure

I expected this code snippet to produce the original vector, but sorted in a case-insensitive way. Instead I get the original vector untouched. Why doesn't my comparator work?
user=> (ns user (require [clojure.contrib.string :as str]))
nil
user=> (sort
(comparator #(compare (str/upper-case %1) (str/upper-case %2)))
["B" "a" "c" "F" "r" "E"])
("B" "a" "c" "F" "r" "E")

comparator returns a java.util.Comparator when given a predicate (a function which returns true or false). You don't need it if you're using compare explicitly. So just:
(sort #(compare (str/upper-case %1) (str/upper-case %2))
["B" "a" "c" "F" "r" "E"])
;=> ("a" "B" "c" "E" "F" "r")
Alternatively, use sort-by:
(sort-by str/upper-case ["B" "a" "c" "F" "r" "E"])
;=> ("a" "B" "c" "E" "F" "r")

compare is not a predicate, it's a comparator.

Related

Explanation for combination of cycle drop and take in clojure

I am trying to understand the implementation of rotating a sequence to which the answer i find in git hub is below
(fn [n coll]
(take (count coll) (drop (mod n (count coll)) (cycle coll))))
Could you please explain what is exacty happening here
(take 6 (drop 1 (cycle ["a" "b" "c"])))
("b" "c" "a" "b" "c" "a")
How is this being produced
From the documentation of cycle:
Returns a lazy (infinite!) sequence of repetitions of the items in coll.
So in your example:
(cycle ["a" "b" "c"])
;; => ["a" "b" "c" "a" "b" "c" "a" "b" "c" "a" "b" "c" ...]
(toward infinity and beyond)
To cut down an infinite sequence, you have to use take which takes the first n element of a sequence. So:
(take 6 (cycle ["a" "b" "c"]))
;; => ["a" "b" "c" "a" "b" "c"]
In your example, just before calling take, you use drop which left out the first n element of a sequence. So:
(drop 1 (cycle ["a" "b" "c"]))
;; => ["b" "c" "a" "b" "c" "a" "b" "c" "a" "b" "c" ...]
(take 6 (drop 1 (cycle ["a" "b" "c"])))
;; => ["b" "c" "a" "b" "c" "a"]
You can learn more about lazy sequences from this chapter of "Clojure from the Brave and True".

Vector Of Maps From Lists

How would I get the following:
[{:foo "a" :bar "b" :biz "c"}
{:foo "d" :bar "e" :biz "f"}
{:foo "h" :bar "i" :biz "j"}]
from
("a" "d" "h")
("b" "e" "i")
("c" "f" "j")
Thanks in advance!
You can transpose the input using map and zipmap to create the result maps:
(def input ['("a" "d" "h")
'("b" "e" "i")
'("c" "f" "j")])
(mapv #(zipmap [:foo :bar :biz] %) (apply map vector input))
this is very alike the #lee's variant, but does it in one pass, employing the clojure map's ability to operate on multiple collections:
(def input ['("a" "d" "h")
'("b" "e" "i")
'("c" "f" "j")])
(apply mapv #(zipmap [:foo :bar :biz] %&) input)
;;=> [{:foo "a", :bar "b", :biz "c"}
;; {:foo "d", :bar "e", :biz "f"}
;; {:foo "h", :bar "i", :biz "j"}]
map can take operate on multiple sequences. When given multiple sequences, it will take elements from each and call your function with them like so:
(let [s1 '("a" "d" "h")
s2 '("b" "e" "i")
s3 '("c" "f" "j")]
(map (fn [x y z]
{:foo x :bar y :baz z})
s1 s2 s3))
;; =>
({:foo "a", :bar "b", :baz "c"}
{:foo "d", :bar "e", :baz "f"}
{:foo "h", :bar "i", :baz "j"})

Clojure Convert PersistentVector of strings to PersistentVector of keywords

Given the following vector: ["a" "b" "c"] how can I convert it to [:a :b :c]
You can use mapv:
(mapv keyword ["a" "b" "c"])
(vec (map keyword ["a" "b" "c"]))

map-indexed function on arbitrary number of collections

There is a map-indexed function in Clojure, however (as of version "1.8.0"), it only accepts up to two arguments (source):
As I could not see any reason not to have an arbitrary number of arguments, I am trying to write my own version (reusing the existing map-indexed function) :
(defn map-index
"like clojure.core/map-indexed but accepts more than two arguments"
([f] ;;(partial (map f (range))) ;; TODO transducer ?
)
([f coll] (map f (range) coll))
([f c1 c2] (map f (range) c1 c2))
([f c1 c2 c3] (map f (range) c1 c2 c3))
([f c1 c2 c3 & colls]
;; Warning !
;; calling map-indexed with a final parameter freezes my REPL
(map f (conj colls c3 c2 c1 (range)))))
((map-indexed list) ["a" "b" "c"])
(map-indexed list ["a" "b" "c"])
((map-index list) ["a" "b" "c"]) ;; KO
(map-index list ["a" "b" "c"])
(map-index list ["a" "b" "c"] ["d" "e" "f"]) ;; OK
(map-index list ["a" "b" "c"] ["d" "e" "f"] ["g" "h" "i"]) ;; OK
(map-index list ["a" "b" "c"] ["d" "e" "f"] ["g" "h" "i"] ["k" "l" "m"]) ;; freezes the REPL
How should I write this map-index function ?
I would just write it like this:
(defn map-index
([f]
(map-indexed f))
([f & colls]
(apply map f (range) colls)))
Unless you really care about performance, there's no need to overcomplicate things with extra arities.
It's worth noting that since the transducer version here simply calls map-indexed, it won't work for an arbitrary number of collections. I'll leave it up to you to implement that if you need to do so.

How to evaluate sequence of pure functions in Clojure

My question is pretty similar to this one: How to evaluate a sequence of impure functions in Clojure? but instead of impure functions, how can I evaluate sequence of pure functions and get the results as another sequence?
Let's assume we have a vector of functions like:
[#(str "a" "b") #(str "c" "d") #(str "e" "f")]
And we need an output like this:
("ab" "cd" "ef")
I've tried something similar to this:
(map eval [#(str "a" "b") #(str "c" "d") #(str "e" "f")])
but it just returns a vector of function references.
There are multiple ways to do what you are asking. It depends on whether you want a lazy sequence or not (you probably want lazy given there are no side-effects, but you might want no-lazy if there's an intensive computation that you want to cache), or if you want a vector as output (the same as your input). I'll try to follow what you tried to do.
Your map with eval is doing the following with each fn:
user=> (eval #(str 1))
#<user$eval1332$fn__1333 user$eval1332$fn__1333#38747597>
But you want something like the following:
user=> (eval (#(str 1)))
"1"
You want eval to have the fn applied, that is: the fn should be the first element of a list. Let's put it in a list:
user=> (map (comp eval list) [#(str "a" "b") #(str "c" "d") #(str "e" "f")])
("ab" "cd" "ef")
Cool. But instead of eval, you probably want to use apply:
user=> (apply #(str 1))
; ArityException Wrong number of args (1)
Ups! It failed. apply doesn't have a 0-arity overload, but we can pass an empty list:
user=> (apply #(str 1) ())
"1"
Much better. Let's do it with map:
user=> (map #(apply % ()) [#(str "a" "b") #(str "c" "d") #(str "e" "f")])
("ab" "cd" "ef")
Or better yet, given your functions receive no arguments, you'd better do as suggested by #Magos:
user=> (map #(%) [#(str "a" "b") #(str "c" "d") #(str "e" "f")])
("ab" "cd" "ef")
You could use (fn [f] (f)) or #(%) in your map.
eval evaluates a Clojure form (i.e., a list containing "code"). You have functions, not forms.
You map with apply, but apply takes both a function and a seq of arguments. Since you have no arguments, you can use the empty vector:
(map apply
[#(str "a" "b") #(str "c" "d") #(str "e" "f")]
(repeat []))
But it would be shorter and probably clearer if you use for:
(for [f [#(str "a" "b") #(str "c" "d") #(str "e" "f")]]
(f))
Note
As Nathan Davis wrote, eval evaluates a clojure form:
(eval '(+ 1 1)) ;=> 2
What does it do to a function? Nothing!. eval treats functions as literals:
((eval +) 1 1) ;=> 2
For your case:
(def stuff [#(str "a" "b") #(str "c" "d") #(str "e" "f")])
... we have
(= stuff (map eval stuff)) ;=> true
Though
(= [#(str "a" "b") #(str "c" "d") #(str "e" "f")]
(map eval [#(str "a" "b") #(str "c" "d") #(str "e" "f")]))
;=> false
... since the corresponding functions are different objects, though identical in operation.
That's why eval is useless to you. So follow Magos's advice.
Maybe it's worth to have a look at pcalls and/or pvalues
(pcalls #(str "a" "b") #(str "c" "d") #(str "e" "f"))
;=> ("ab" "cd" "ef")
Please note that pcalls is using future inside!