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
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".
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"})
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"]))
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.
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!