Is there a way to use the * and + operands with strings in Clojure?
For example:
(defn times [a b] (* a b))
=> (times x y)
Desired Output: x*y
OR
Desired Output: xy
I don't see a problem:
(defn * [a b]
(if (and (string? a) (string? b))
(str a b)
(clojure.core/* a b)))
WARNING: * already refers to: #'clojure.core/* in namespace: user, being replaced by: #'user/*
=> #'user/*
(* 4 5)
=> 20
(* "A" "B")
=> "AB"
I'm assuming that you're using Clojure on the JVM.
The function * only works with numbers.
You can convert a String into a number by parsing it to the right type:
(def int1 (Integer/parseInt "1"))
(def double1 (Double/parseDouble "1.0"))
(def product1 (* int1 double1)) ;; 2.0
;; or
(def int2 (clojure.edn/read-string "1"))
(def double2 (clojure.edn/read-string "1.0"))
(def product2 (* int2 double2)) ;; 2.0
Related
I have been writing a fairly simple piece of code to get the hang of Clojure and I've run into an issue where when I pass each line into a REPL in order (while using a test case to substitute the values that would be passed as part of the function), I get the expected result but when I try to compile it as a function I get the error Execution error (ClassCastException) at testenv.core/sum-of-two-largest-squares (core.clj:14). class clojure.lang.PersistentList cannot be cast to class clojure.lang.IFn (clojure.lang.PersistentList and clojure.lang.IFn are in unnamed module of loader 'app')
The relevant function is as follows (note that I've moved each step into variables in order to figure out the problem)
(defn sum-of-two-largest-squares [a b c]
(
(def x (into () (map math/abs [a b c])))
(def m (apply min x))
(def y (into () (map square (remove (fn [n] (= n m)) x))))
(apply + y)
)
)
You can't just put parenthesis around things without expecting it to change the meaning.
What works when run in a REPL is:
(defn abs [n] (java.lang.Math/abs n))
(defn square [n] (* n n))
(def x (into () (map abs [a b c])))
(def m (apply min x))
(def y (into () (map square (remove (fn [n] (= n m)) x))))
(apply + y)
...and strictly, this still works if injected into a function, as long as you take out the extra parenthesis (though it works slowly and with unwanted side effects due to the inappropriate use of def):
(defn sum-of-two-largest-squares [a b c]
(def x (into () (map abs [a b c])))
(def m (apply min x))
(def y (into () (map square (remove (fn [n] (= n m)) x))))
(apply + y)
)
(sum-of-two-largest-squares a b c)
However, a good-practice alternative would use let instead:
(defn abs [n] (java.lang.Math/abs n))
(defn square [n] (* n n))
(defn sum-of-two-largest-squares [a b c]
(let [x (into () (map abs [a b c]))
m (apply min x)
y (into () (map square (remove (fn [n] (= n m)) x)))]
(apply + y)))
Here is a more typical solution to this problem
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(defn square [x] (* x x))
(defn sum-of-two-largest-squares [a b c]
(let-spy
[sorted (sort [a b c])
largest-two (rest sorted)
squares (mapv square largest-two)
result (apply + squares)]
result))
(dotest
(is= 41 (spyx (sum-of-two-largest-squares 3 4 5)))
)
with result:
-----------------------------------
Clojure 1.10.3 Java 15.0.2
-----------------------------------
Testing tst.demo.core
sorted => (3 4 5)
largest-two => (4 5)
squares => [16 25]
result => 41
(sum-of-two-largest-squares 3 4 5) => 41
Ran 2 tests containing 0 assertions.
0 failures, 0 errors.
It uses my favorite template project. Just change let-spy back to let once finished writing/debugging.
I've written a probability function in Clojure that takes an optional hash-map of options:
(defn roll-lte
([n d] (/ n d))
([n d options]
(let [p (/ n d)
roll-type (:type options :normal)]
(cond
(= roll-type :advantage) (- (* p 2) (* p p))
(= roll-type :disadvantage) (* p p)
(= roll-type :normal) p
:else (throw (IllegalArgumentException. "Invalid roll type."))))))
This works as intended, but the idea is to write other functions that build off of this one -- for example:
(defn roll-gte
([n d] (roll-lte (- d n -1) d))
([n d options] (roll-lte (- d n -1) d options)))
The two arities in roll-lte make building off of the function awkward and repetitive, especially in cases like the above where options is simply being forwarded to roll-lte. Is there a more concise and less repetitive way to achieve this?
When I have functions with multiple arities, I usually try to have the lower-arity versions call the higher-arity versions with safe default arguments. The "main" implementation of the function usually ends up being the highest-arity body:
(defn roll-lte
([n d] (roll-lte n d nil))
([n d {:keys [type]
:or {type :normal}}]
(let [p (/ n d)]
(case type ;; used case instead of cond here
:advantage (- (* p 2) (* p p))
:disadvantage (* p p)
:normal p
(throw (IllegalArgumentException. "Invalid roll type."))))))
I also used :or in the options map destructuring above to set the default value for type, which allows the lower-arity functions to just pass a nil options map.
(defn roll-gte
([n d] (roll-gte n d nil))
([n d options] (roll-lte (- d n -1) d options)))
(roll-gte 3 4) ;=> 1/2
(roll-gte 3 4 {:type :advantage}) ;=> 3/4
I would like to create a lazy sequence that repeats elements from another collection. It should generate one of each element before repeating. And the order of elements must be random.
Here's what it should behave like:
=> (take 10 x)
(B A C B A C A B C C)
This seems to work:
(def x (lazy-seq (concat (lazy-seq (shuffle ['A 'B 'C])) x)))
However it is using two lazy-seq's. Is there a way to write this sort of lazy sequence by using just one lazy-seq?
If this cannot be done with one lazy-seq, how do values get generated? Since my collection has only three items, I expect the inner lazy-seq to be calculated completely in the first chunk.
Before coming up with the sequence above I tried the one below:
=> (def x (lazy-seq (concat (shuffle ['A 'B 'C]) x)))
=> (take 10 x)
(C A B C A B C A B C)
I would appreciate any explanation why this one doesn't randomize each batch.
How about just repeating the sequence and then mapcatting over it with the shuffle function? Here is an example:
(take 10 (mapcat shuffle (repeat ['A 'B 'C])))
;=> (B C A B A C B A C B)
I would appreciate any explanation why this one doesn't randomize each batch.
Your (shuffle '[a b c]) is evaluated only once, when beginning of the sequence is realized, then the shuffled list is used again and again.
Here is a little test:
user> (defn test-fnc [coll]
(do (print "boom!")
(shuffle coll)))
;; => #'user/test-fnc
user> (def x (lazy-seq (concat (test-fnc '[a b c]) x)))
;; => #'user/x
user> (take 10 x)
;; => (boom!b c a b c a b c a b)
user> (take 10 x)
;; => (b c a b c a b c a b)
You also can use lazy-cat instead:
user> (def x (lazy-cat (shuffle '[a b c]) x))
;; => #'user/x
but is won't solve your problem :-)
This happens because of lazy-seq:
Takes a body of expressions that returns an ISeq or nil, and yields a Seqable object that will invoke the body only the first time seq is called, and will cache the result and return it on all subsequent seq calls.
If you rewrite your definition in terms of function calls:
(defn x [] (lazy-seq (concat (shuffle ['A 'B 'C]) (x))))
it will work:
user> (take 10 (x))
;; => (C B A C A B B A C B)
because there will be different lazy seq on every call, not the same cached seq that repeats itself.
I'm attempting to write the Lp norm function as to generalize the standard L2 norm (Euclidean distance) used. Here is what I have come up with so far, given how I had written the L2 norm:
(defn foo [a b p]
(reduce + (map (comp (map #(power a %) p) -) a b)))
However I am getting the error ClassCastException whenever I try to implement this function. Part of the interim code is from a previously asked question Raising elements in a vector to a power where the following code was provided:
(defn compute [exp numbers]
(map #(power exp %) numbers))
Consider factoring your code.
First define the p-norm
(defn p-norm [p x]
(if (= p :infinity)
(apply max (for [xi x] (Math/abs xi)))
(Math/pow
(reduce + (for [xi x] (Math/pow xi p)))
(/ 1 p))))
And then use the p-norm to define your p-metric
(defn p-metric [p x y]
(p-norm p (map - x y)))
Example
(p-metric 2 [0 0] [3 4])
;=> 5.0
(p-metric :infinity [0 0] [3 4])
;=> 4
Your inner (map):
(map #(power a %) p)
Returns a sequence and you can't feed that to (comp). 'comp' is for 'Function Composition'.
In the REPL:
(doc comp)
clojure.core/comp
([] [f] [f g] [f g h] [f1 f2 f3 & fs])
Takes a set of functions and returns a fn that is the composition
of those fns. The returned fn takes a variable number of args,
applies the rightmost of fns to the args, the next
fn (right-to-left) to the result, etc.
Start breaking your code into smaller steps. (let) form is quite handy, don't be shy to use it.
I need to define a function which takes a sequence and some functions which act on elements inside the sequence. It returns a sequence from the old sequence where the elements with duplicate function values are removed.
(defn dedup [seq & functions] ...)
for example, if
(f1 1) = 'a'
(f1 2) = 'a'
(f1 3) = 'c'
(f1 4) = 'd'
(f2 1) = 'za'
(f2 2) = 'zb'
(f2 3) = 'zc'
(f2 4) = 'zb'
then
(dedup [1 2 3 4] f1 f2)
returns a sequence of (1 3)
how do I do it?
EDIT:
edited the test values so as not to create misunderstanding
EDIT:
Below is the (not so functional) implementation for the case of only 1 function
(defn dedup [seq f]
(loop [values #{} seq1 seq seq2 '()]
(let [s (first seq1)]
(if (nil? s)
(reverse seq2)
(let [v (f s)]
(if (contains? values v)
(recur values (rest seq1) seq2)
(recur (conj values v) (rest seq1) (conj seq2 s))))))))
your example seems to contradict the text - it is returning values where the two functions agree.
(defn dedup [seq & fns]
(for [s seq :when (apply = (map #(% s) fns))] s))
(dedup [1 2 3 4]
#(case % 1 "a" 2 "a" 3 "c" 4 "d")
#(case % 1 "a" 2 "b" 3 "c" 4 "b"))
(1 3)
maybe that's a little too compact? #(... % ...) is equivalent to (fn [x] (... x ...)) and the map in dup runs over the functions, applying them all to the same value in the sequence.
you could also test with
(dedup [1 2 3 4] {1 "a" 2 "a" 3 "c" 4 "d"} {1 "a" 2 "b" 3 "c" 4 "b"})
(1 3)
ps i think maybe the confusion is over english meaning. "duplicate" means that a value repeats. so "a" "a" is a duplicate of "a". i suspect what you meant is "multiple" - you want to remove entries where you get multiple (distinct) values.
pps you could also use filter:
(defn dedup [seq & fns]
(filter #(apply = (map (fn [f] (f %)) fns)) seq))
where i needed to write one anonymous function explicitly because you can't nest #(...).