The Clojure distinct? method doesn't take a collection, but rather a list of args
(distinct? x)
(distinct? x y)
(distinct? x y & more)
So (distinct? 0 0 0 0) correctly returns false, while (distinct? [0 0 0 0]) returns true. How can I use distinct? on a collection so that passing it a collection [0 0 0 0] would return false since the collection contains duplicates?
I do realize that the function is performing correctly, but I'm looking for a trick to apply it to the contents of a collection instead of a list of args.
As a workaround, I currently have
(defn coll-distinct? [coll]
(= (distinct coll) coll))
but I feel like I'm missing a more elegant way reusing distinct?
If you want to pass arguments as a seq to a function, use apply.
(apply distinct? [1 2 3 1])
; false
(apply distinct? [1 2 3])
; true
Related
I was wondering today if i have a list of numbers. Is there a function in ClojureScript which returns a number made from the numbers by place value? (I dont mean a list(), but just some numbers)
For e.g.:
I have a some numbers 1, 2, 3, and i am looking for a function which converts it to 123 (one hundred and twenty-three).
I thought I found a solution for this with read-string
(read-string (str 1 2 3))
;=> 123
but sadly it not works well if i want to use it in the function discussed below.
I have a "functionmade" map where keys are vectors and values are numbers. Like this:
{[0 0] 0, [0 1] 1, ... [4 5] 45, ... [9 9] 99}
The only way i can use get function on this map is:
(get {[0 2] 2} [0 2])
;=> 2
; or
(get {[4 5] 45} [4 5])
;=> 45
This is grinding, but it works. To make it look much better i tried to define a function where i used read-string: (read/ refers to cljs.reader)
(defn get-oxo [x y]
(get {[x y] (read/read-string (str x y))} [x y]))
;So i can use it like this for e.g.:
(get-oxo 4 5)
;=> 45
It also returns values which are not in the map:
(get-oxo 112 358)
;=> 112358
I suppose the problem is that this way get-oxo returns not the value of the paired key, but the number constructed from x y...
So the questions is how can I fix it to return the value of the paired key and not the number constructed from the numbers i give to the functions?
(There is another problem if i want to generate a map with wider range of numbers, for e.g. not just 0-9 but 0-99. This way the algorythm of get-oxo is not true. I use the function discussed at: ClojureScript zipmap tricks me or what?).
the problem is you get what you put:
just decompose your function to see it clearly:
(defn get-oxo [x y]
(let [new-map {[x y] (read/read-string (str x y))}]
(println new-map)
(get new-map [x y])))
#'user/get-oxo
user> (get-oxo 100 200)
;;=> {[100 200] 100200}
;;=> 100200
So you generate your map inside the function, and get it's key
and you get... a totally valid behavior
to get something from your map , you need to have your map as the first argument of get function
(defn get-oxo [input x y]
(get input [x y]))
#'user/get-oxo
user> (def data {[0 0] 0 [0 1] 1 [0 2] 2})
#'user/data
user> (get-oxo data 0 1)
1
user> (get-oxo data 2 3)
nil
then, if you need the key (i mean pair from map) instead of value, you can modify it this way, using find function instead of get:
(defn get-oxo [input x y]
(first (find input [x y])))
#'user/get-oxo
user> (get-oxo data 0 1)
[0 1]
user> (get-oxo data 2 3)
nil
also writing and reading string to get a number looks redundant. You can easily make a simple function for that:
(defn digits->num [digits]
(reduce (fn [acc d] (+ (* 10 acc) d))
0
digits))
#'user/digits->num
user> (digits->num [0])
0
user> (digits->num [])
0
user> (digits->num [1])
1
user> (digits->num [1 2 3 4])
1234
user> (digits->num [0 0 1 0])
10
You can simply apply str function to your sequence of digits:
(apply str '(1 2 3))
;; => "123"
Hello I have a simple function like this:
(def state
(memoize
(fn state [t]
(if (<= t 0)
0
1))))
on which I am trying to call (reduce state (range 10)) which the intent of calling the function state on the range 0 1 2 3 4 5 ..., and receiving back 0 1 1 1 1 1 1 1 1 1.
That is not happening, thus I am obviously misunderstanding something, since I am getting:
clojure.lang.ArityException: Wrong number of args (2) passed to: state
The syntax for reduce is (reduce f coll) and my understanding was that it is as simple as doing (reduce + [1 2 3 4 5]).
Obviously one can do this easily enough with map I was just under the impression that reduce would work as well. With map, (map (fn [x] (state x)) (range 10)).
PS. this is just a test case, I genuinely do need memoization for the real thing.
Thanks
Obviously one can do this easily enough with map I was just under the impression that reduce would work as well.
Yes. Any map can also be a reduce. (Except reduce is not lazy, while map is).
The result of a reduce function is going to be the result that is returned in the end after N iterations of your function over your reduction range.
Your function returns a 0 or a 1, therefore, your reduce will ultimately return either a 0 or 1.
If you want to return a list, then your reduction function needs to return a list. Or, use a function other than reduce, such as map.
Also -- all reduction functions take 2 arguments, not 1. So your state function is not a valid function to pass to reduce. Though, it is a valid function to pass to map.
Incidentally, you can do this with reduce, you don't need map -- in fact, many functions can be expressed as reduce, including map, filter and others. But, you'd need to alter your reduction function to make it compatible.
The comments and other answers suggest you must use map, but here is a reduce that will do it:
(def state
(memoize
(fn state [r t]
(if (<= t 0)
(conj r 0)
(conj r 1)))))
(reduce state [] (range 10))
;;-> [0 1 1 1 1 1 1 1 1 1]
This is a great idiom when you have logic for the value of a particular item that depends on knowing about the other items. You do not have such logic here, so map is a better choice. But conceptually you can express many things in functional programming in terms of a fold which is what reduce is.
Here is an alternate method, keeping the original state function from the question, and therefore its memoization intact:
(def state
(memoize
(fn state [t]
(if (<= t 0)
0
1))))
(defn r-fn [r t]
(conj r (state t)))
(reduce r-fn [] (range 10))
;;-> [0 1 1 1 1 1 1 1 1 1]
This is more succinctly written as:
(reduce #(conj %1 (state %2)) [] (range 10))
well, that's because the reduce function should take exactly 2 parameters: accumulator and item from the coll, bur in case the accumulator is not provided during reduce call, the first step of reduction is applied to first 2 values from coll:
(reduce + '(1 2 3 4)) is really (+ (+ (+ 1 2) 3) 4)
but that's not what you need in your case:
user> (map state (range 10))
(0 1 1 1 1 1 1 1 1 1)
as you don't want to reduce a coll to a single value, but rather map each value to another
I'm sorry if this is a truly basic question, but some code I've seen got me curious.
What is the idiomatic usage of the apply function?
For instance, I've seen code written in the form:
(distinct [1 2 3 4 5 6])
and
(apply distinct? [1 2 3 4 5 6])
These return the same result, and even in the docs, it clearly says:
;; Note the equivalence of the following two forms
user=> (apply str ["str1" "str2" "str3"]) "str1str2str3"
user=> (str "str1" "str2" "str3") "str1str2str3"
Is this example simply too basic to convey the usefulness of apply? Or am I missing a fundamental difference between the two?
When is one form regarded as best over the other?
user=> (apply str ["str1" "str2" "str3"]) "str1str2str3"
user=> (str "str1" "str2" "str3") "str1str2str3"
In this example, the advantage of using apply is that it can take a list of strings. str, by itself, cannot.
I'm no expert, but my instinct says that you shouldn't use apply unless necessary. Therefore, if you have a collection of values that you want to pass to a variadic function, apply is useful — otherwise, just use the plain function, e.g. str.
These are both true, but for very different reasons:
(distinct? [1 2 3 4 5 6])
;=> true
There is only one argument, the vector of 1..6,
and it is distinct from any other argument because there
are no other arguments
(apply distinct? [1 2 3 4 5 6])
;=> true
There are 6 arguments, all of which are distinct.
Observe:
(distinct? [1 1 1])
;=> true
There is only one argument, the vector of three 1s
(apply distinct? [1 1 1])
;=> false
There are three arguments, all three of which are 1.
Note the difference:
(str [1 2 3])
;=> "[1 2 3]" -- single argument of a vector stringified
(apply str [1 2 3])
;=> "123" -- three arguments each stringified and concatenated
Apply effects the transformation (apply f [a b c]) => (f a b c), which is generally not the same as (f [a b c]).
Use apply when you want to treat a collection as the arguments of a function. In the case of distinct it takes a collection as it's argument, so it's not necessary to use apply.
(distinct [1 2 3 4 1 1])
;returns: (1 2 3 4)
distinct? returns true if it's arguments are distinct:
(distinct? [1 2 3 4 1 1])
;returns true because there's only one argument
apply uses the items in the collection as arguments:
(apply distinct? [1 2 3 4 1 1])
;returns false because of the duplicated 1's
Generally, I use apply to transform a vector to arguments when calling a function. This is a lot like the apply function found in JavaScript as shown here
Functions such as str are variadic and expect the same type as input, in this case, anything that implements toString. Using (str a b c) is idiomatic, (apply str [a b c]) is not.
The function apply can be used when you have a heterogeneous vector whose items you would like to use as arguments to a function. You may find the need to create a list of vectors where the items in the vector correspond to the arguments of your function, then it's necessary to use apply.
I think of apply as: exploding the vector into arguments.
Example:
(def authtypes [:basic :basic :oauth])
(def usernames ["charlie" "snoopy" "lisa"])
(def passwords ["brown" "dog" "maggie"])
(let [credentials (map vector authtypes usernames passwords)]
(doseq [c credentials]
(apply login-user c)))
The comprehension:
(for [i (range 5])] i)
... yields: (0 1 2 3 4)
Is there an idiomatic way to get (0 0 1 1 2 4 3 9 4 16) (i.e. the numbers and their squares) using mostly the for comprehension?
The only way I've found so far is doing a:
(apply concat (for [i (range 5)] (list i (* i i))))
Actually, using only for is pretty simple if you consider applying each function (identity and square) for each value.
(for [i (range 5), ; for every value
f [identity #(* % %)]] ; for every function
(f i)) ; apply the function to the value
; => (0 0 1 1 2 4 3 9 4 16)
Since for loops x times, it will return a collection of x values. Multiple nested loops (unless limited by while or when) will give x * y * z * ... results. That is why external concatenation will always be necessary.
A similar correlation between input and output exists with map. However, if multiple collections are given in map, the number of values in the returned collection is the size of the smallest collection parameter.
=> (map (juxt identity #(* % %)) (range 5))
([0 0] [1 1] [2 4] [3 9] [4 16])
Concatenating the results of map is so common mapcat was created. Because of that, one might argue mapcat is a more idiomatic way over for loops.
=> (mapcat (juxt identity #(* % %)) (range 5))
(0 0 1 1 2 4 3 9 4 16)
Although this is just shorthand for apply concat (map, and a forcat function or macro could be created just as easily.
However, if an accumulation over a collection is needed, reduce is usually considered the most idiomatic.
=> (reduce (fn [acc i] (conj acc i (* i i))) [] (range 5))
[0 0 1 1 2 4 3 9 4 16]
Both the for and map options would mean traversing a collection twice, once for the range, and once for concatenating the resulting collection. The reduce option only traverses the range.
Care to share why "using mostly the for comprehension" is a requirement ?
I think you are doing it right.
A slightly compressed way maybe achieved using flatten
(flatten (for [i (range 5)] [ i (* i i) ] ))
But I would get rid of the for comprehension and just use interleave
(let [x (range 5)
y (map #(* % %) x)]
(interleave x y))
Disclaimer: I am just an amateur clojurist ;)
I have this deeply nested list (list of lists) and I want to replace a single arbitrary element in the list. How can I do this ? (The built-in replace might replace many occurrences while I need to replace only one element.)
As everyone else already said, using lists is really not a good idea if you need to do this kind of thing. Random access is what vectors are made for. assoc-in does this efficiently. With lists you can't get away from recursing down into the sublists and replacing most of them with altered versions of themselves all the way back up to the top.
This code will do it though, albeit inefficiently and clumsily. Borrowing from dermatthias:
(defn replace-in-list [coll n x]
(concat (take n coll) (list x) (nthnext coll (inc n))))
(defn replace-in-sublist [coll ns x]
(if (seq ns)
(let [sublist (nth coll (first ns))]
(replace-in-list coll
(first ns)
(replace-in-sublist sublist (rest ns) x)))
x))
Usage:
user> (def x '(0 1 2 (0 1 (0 1 2) 3 4 (0 1 2))))
#'user/x
user> (replace-in-sublist x [3 2 0] :foo)
(0 1 2 (0 1 (:foo 1 2) 3 4 (0 1 2)))
user> (replace-in-sublist x [3 2] :foo)
(0 1 2 (0 1 :foo 3 4 (0 1 2)))
user> (replace-in-sublist x [3 5 1] '(:foo :bar))
(0 1 2 (0 1 (0 1 2) 3 4 (0 (:foo :bar) 2)))
You'll get IndexOutOfBoundsException if you give any n greater than the length of a sublist. It's also not tail-recursive. It's also not idiomatic because good Clojure code shies away from using lists for everything. It's horrible. I'd probably use mutable Java arrays before I used this. I think you get the idea.
Edit
Reasons why lists are worse than vectors in this case:
user> (time
(let [x '(0 1 2 (0 1 (0 1 2) 3 4 (0 1 2)))] ;'
(dotimes [_ 1e6] (replace-in-sublist x [3 2 0] :foo))))
"Elapsed time: 5201.110134 msecs"
nil
user> (time
(let [x [0 1 2 [0 1 [0 1 2] 3 4 [0 1 2]]]]
(dotimes [_ 1e6] (assoc-in x [3 2 0] :foo))))
"Elapsed time: 2925.318122 msecs"
nil
You also don't have to write assoc-in yourself, it already exists. Look at the implementation for assoc-in sometime; it's simple and straightforward (compared to the list version) thanks to vectors giving efficient and easy random access by index, via get.
You also don't have to quote vectors like you have to quote lists. Lists in Clojure strongly imply "I'm calling a function or macro here".
Vectors (and maps, sets etc.) can be traversed via seqs. You can transparently use vectors in list-like ways, so why not use vectors and have the best of both worlds?
Vectors also stand out visually. Clojure code is less of a huge blob of parens than other Lisps thanks to widespread use of [] and {}. Some people find this annoying, I find it makes things easier to read. (My editor syntax-highlights (), [] and {} differently which helps even more.)
Some instances I'd use a list for data:
If I have an ordered data structure that needs to grow from the front, that I'm never going to need random-access to
Building a seq "by hand", as via lazy-seq
Writing a macro, which needs to return code as data
For the simple cases a recursive substitution function will give you just what you need with out much extra complexity. when things get a little more complex its time to crack open clojure build in zipper functions: "Clojure includes purely functional, generic tree walking and editing, using a technique called a zipper (in namespace zip)."
adapted from the example in: http://clojure.org/other_libraries
(defn randomly-replace [replace-with in-tree]
(loop [loc dz]
(if (zip/end? loc)
(zip/root loc)
(recur
(zip/next
(if (= 0 (get-random-int 10))
(zip/replace loc replace-with)
loc)))))
these will work with nested anything (seq'able) even xmls
It sort of doesn't answer your question, but if you have vectors instead of lists:
user=> (update-in [1 [2 3] 4 5] [1 1] inc)
[1 [2 4] 4 5]
user=> (assoc-in [1 [2 3] 4 5] [1 1] 6)
[1 [2 6] 4 5]
So if possible avoid lists in favour of vectors for the better access behaviour. If you have to work with lazy-seq from various sources, this is of course not much of an advice...
You could use this function and adapt it for your needs (nested lists):
(defn replace-item
"Returns a list with the n-th item of l replaced by v."
[l n v]
(concat (take n l) (list v) (drop (inc n) l)))
A simple-minded suggestion from the peanut gallery:
copy the inner list to a vector;
fiddle that vector's elements randomly and to your heart's content using assoc;
copy the vector back to a list;
replace the nested list in the outer list.
This might waste some performance; but if this was a performance sensitive operation you'd be working with vectors in the first place.