This question already has answers here:
How do I find the index of an item in a vector?
(9 answers)
Closed 8 years ago.
I want to write a program in clojure that would return only the first index value of true values from my function. My code goes here:
(defn func [f x] (map f x))
So, if I give a value like:
(func zero? [1 1 1 0 3 7 0 2])
It gives me:
(false false false true false false true false)
and if I give:
(func (fn [n] (= n 6)) [:cat :dog :six :blorg 6])
It returns:
(false false false false true)
But, what I want is index value of first true. Like for
(func zero? [1 1 1 0 3 7 0 2]) => 3 (desired result)
(func (fn [n] (= n 6)) [:cat :dog :six :blorg 6]) => 4 (desired result)
(func zero? [1 1 3 7 2]) => nil (desired result)
Can anybody suggest how to get the first index value of true?
(count (take-while not '(false false false true false false true false)))
=> 3
(.indexOf '(false true) true)
=> 1
The answer you posted yourself seems slightly overcomplicated. It can be simplified to this:
(defn first-indexed [pred coll]
(first (keep-indexed (fn [idx itm]
(when (pred itm)
idx))
coll)))
i.e. the true? (vec (map part of tun is unnecessary.
Ok, so I found out an answer for my question itself:
(defn indices [pred coll]
(keep-indexed #(when (pred %2) %1) coll))
(defn tun [f x]
(first (indices true?
(vec (map f x)))))
and if you do:
(tun zero? [1 1 3 7 2]) => nil (the exact desired result)
Related
Im starting to learn Clojure from the scratch and im stucked on my function. Im trying to find the sum of all the multiples of 3 or 5 below 1000. THis is what i did.
(defn suma [x sum]
(cond
(= (/ x 3) 0)(let [sum (+ sum x)])
(= (/ x 5) 0)(let [sum (+ sum x)])))
(defn main[]
(def sum 0)
(def x 3)
(while(< x 1001)
(do
(suma sum x)
(let [x (+ x 1)]))
(str "Total = " sum)))
I tried several things, but i cant figure out what's wrong....
Any help will be apreciated.
Thanks
EDIT:
Fixed, the problem was on the let, it was not updating the value of the data. Here the solution:
(defn suma [x sum]
(cond
(zero? (mod x 3))(alter-var-root #'sum (constantly (+ sum x)))
(zero? (mod x 5))(alter-var-root #'sum (constantly (+ sum x)))))
(defn main[]
(def sum 0)
(def x 3)
(while(< x 1001)
(do
(suma x sum)
(alter-var-root #'x inc)))
(str "TOTAL = " sum))
A simple solution using the sequence library is
(->> (concat
(range 0 1000 3)
(range 0 1000 5))
distinct
(apply +))
If you want to do it in an iterative style, Don't use while, which depends on side effects. Use loop and recur, which effect a primitive form of recursion called tail recursion:
(defn divides? [i j]
(zero? (mod j i)))
(loop [answer 0, n 0]
(if (< n 1000)
(recur
(if (or (divides? 3 n) (divides? 5 n))
(+ answer n)
answer)
(inc n))
answer))
Both the above produce the same answer.
Here is an outline using a more functional style. Of course, there is more than one way to do it (TM). :)
> lein repl
user=> (def data (range 20))
user=> data
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)
user=> (defn is-mul-3? [x] (zero? (mod x 3)))
user=> (mapv is-mul-3? data)
[true false false true false false true false false true false false true false false true false false true false]
user=> (defn is-mul-5? [x] (zero? (mod x 5)))
user=> (mapv is-mul-5? data)
[true false false false false true false false false false true false false false false true false false false false]
user=> (defn is-mul-3-or-5? [x] (or (is-mul-3? x) (is-mul-5? x)))
user=> (mapv is-mul-3-or-5? data)
[true false false true false true true false false true true false true false false true false false true false]
user=> (def only-3s-and-5s (filterv is-mul-3-or-5? data))
user=> only-3s-and-5s
[0 3 5 6 9 10 12 15 18]
user=> (apply + only-3s-and-5s)
78
Update:
Here is a more imperitive version. Clojure values (like in let are usually immutable). You must use an atom if you want something like a
mutable Java variable:
(ns clj.core
(:gen-class))
(defn is-mul-3? [x]
(zero? (mod x 3)))
(defn is-mul-5? [x]
(zero? (mod x 5)))
(defn is-mul-3-or-5? [x]
(or (is-mul-3? x)
(is-mul-5? x)))
(defn sum-3s-and-5s [limit]
(let [cum-sum (atom 0) ]
(doseq [curr-val (range limit)]
(if (is-mul-3-or-5? curr-val)
(swap! cum-sum + curr-val)))
#cum-sum ))
(defn -main [& args]
(println "cumsum = " (sum-3s-and-5s 20))
)
with result:
~/clj > lein run
cumsum = 78
I’m having trouble writing an elegant drop-last-by or butlast-by function.
(drop-last-by odd? [2 1 9 4 7 7 3]) ; => (2 1 9 4)
(drop-last-by odd? [2 4]) ; => (2 4)
(drop-last-by odd? [9]) ; => ()
What I have so far works but seems a little clumsy and I wonder if it can be done in just two or three lines.
(defn drop-last-by [pred coll]
(let [p (partition-by pred coll)]
(apply concat (if (and (seq p) (pred (first (last p))))
(butlast p)
p))))
Since drop-while already does basically what you need, and since your current solution is already not lazy, I'd write drop-last-by like this:
(defn drop-last-by [pred coll]
(reverse (drop-while pred (reverse coll))))
The version below is lazy to the degree permitted by the problem specification:
any elements that do not satisfy the predicate are immediately passed through without reading any additional elements from the source;
any elements that do satisfy the predicate are passed through as soon as an element that does not satisfy the predicate is read in from the source;
any elements that satisfy the predicate and are not followed by further elements that do not satisfy the predicate are dropped.
Additionally, it can be used as a (stateful) transducer; indeed the lazy seq version is implemented in terms of the transducer and clojure.core/sequence.
(defn drop-last-by
([pred]
(fn [rf]
(let [xs (volatile! [])]
(fn
([] (rf))
([result] (rf result))
([result input]
(if-not (pred input)
(do
(reduce rf result #xs)
(vreset! xs [])
(rf result input))
(do
(vswap! xs conj input)
result)))))))
([pred coll]
(sequence (drop-last-by pred) coll)))
At the REPL:
(drop-last-by odd? [2 1 9 4 7 7 3])
;= (2 1 9 4)
(drop-last-by odd? [2 4])
;= (2 4)
(drop-last-by odd? [9])
;= ()
Composed with other transducers:
(into []
(comp (drop-while even?)
(drop-last-by odd?)
(map #(str "foo " %)))
[0 1 2 3 4 5])
;= ["foo 1" "foo 2" "foo 3" "foo 4"]
To pad out a sequence with some value, this is what I've come up with:
(defn pad [n coll val]
(take n (concat coll (repeat val))))
(pad 10 [1 2 3] nil) ; (1 2 3 nil nil nil nil nil nil nil)
I'm curious if there's a shorter idiom that does this already and perhaps more efficiently.
Yes this is an idiomatic way of going about padding partitions of a sequence. In fact that code is very similar to part of the partition function in clojure.core the difference being that partition does not assume a single padding value and instead asks for a sequence:
core.clj:
([n step pad coll]
(lazy-seq
...
(list (take n (concat p pad))))))))
You can get the same results by passing a padding collection to partition:
user> (defn pad [n coll val]
(take n (concat coll (repeat val))))
#'user/pad
user> (pad 10 [1 2 3] nil)
(1 2 3 nil nil nil nil nil nil nil)
user> (first (partition 10 10 (repeat nil) [1 2 3]))
(1 2 3 nil nil nil nil nil nil nil)
Here's a lazy version of the padding function:
(defn lazy-pad
"Returns a lazy sequence which pads sequence with pad-value."
[sequence pad-value]
(if (empty? sequence)
(repeat pad-value)
(lazy-seq (cons (first sequence) (lazy-pad (rest sequence) pad-value)))))
You can use it like a regular infinite lazy collection:
(take 5 (lazy-pad [1 2 3] :pad))
=> (1 2 3 :pad :pad)
IMO it's more elegant this way. You can also use it with other functions which expect a lazy sequence, which doesn't work if you have to specify the length upfront:
(partition 2 (interleave [1 2 3 4] (lazy-pad [:a] :pad)))
=> ((1 :a) (2 :pad) (3 :pad) (4 :pad))
I have function that takes any amount of predicates and filters the seq for each one of them like this:
(defn andp [& fns]
(fn [& args]
(every? #(apply % args) fns)))
(defn pred-and
([] "what to return")
([x] x)
([x y] (andp x y))
([x y & more]
(reduce pred-and (pred-and x y) more)
)
)
This works as expected for 1 2 or more params like this:
(filter (pred-and pos? odd?) [1 2 -4 0 6 7 -3]) => [1 7] // For one parameter
(filter (pred-and number? integer? pos? even?) [1 0 -2
:a 7 "a" 2]) => [2] // For two parameters
The problem is when I pass no parameters, it should return the original sequence how to do that?
(filter (pred-and) [1 0 -2]) => [1 0 -2]
as per the docs filter
returns a lazy sequence of the items in coll for which (pred item) returns true.
To get the original sequence, (pred item) must return true for every item.
(fn [x] true) should do the trick.
Look at the function below. I want to pass a vector of factors and test if any of the elements in the vector is a factor of x. How do I do that?
(defn multiple?
"Takes a seq of factors, and returns true if x is multiple of any factor."
([x & factors] (for [e m] ))
([x factor] (= 0 (rem x factor))))
You could try using some and map:
(defn multiple? [x & factors]
(some zero? (map #(rem x %) factors)))
Also some returns nil if all tests fail, if you need it to actually return false, you could put a true? in there:
(defn multiple? [x & factors]
(true? (some zero? (map #(rem x %) factors))))
Note that some short-circuits and map is lazy, so multiple? stops as soon as a match is found. e.g. the following code tests against the sequence 1,2,3,4,....
=> (apply multiple? 10 (map inc (range)))
true
Obviously this computation can only terminate if multiple? doesn't test against every number in the sequence.
You can solve it only using some.
=> (defn multiple? [x factors]
(some #(zero? (rem x %)) factors))
#'user/multiple?
=> (= true (multiple? 10 [3 4]))
false
=> (= true (multiple? 10 [3 4 5 6]))
true
some will stop at the first factor.
Try this, using explicit tail recursion:
(defn multiple? [x factors]
"if any of the elements in the vector is a factor of x"
(loop [factors factors]
(cond (empty? factors) false
(zero? (rem x (first factors))) true
:else (recur (rest factors)))))
The advantages of the above solution include: it will stop as soon as it finds if any of the elements in the vector is a factor of x, without iterating over the whole vector; it's efficient and runs in constant space thanks to the use of tail recursion; and it returns directly a boolean result, no need to consider the case of returning nil. Use it like this:
(multiple? 10 [3 4])
=> false
(multiple? 10 [3 4 5 6])
=> true
If you want to obviate the need to explicitly pass a vector (for calling the procedure like this: (multiple? 10 3 4 5 6))) then simply add a & to the parameter list, just like it was in the question.
A more Clojurian way is to write a more general-purpose function: instead of answering true/false question it would return all factors of x. And because sequences are lazy it is almost as efficient if you want to find out if it's empty or not.
(defn factors [x & fs]
(for [f fs :when (zero? (rem x f))] f))
(factors 5 2 3 4)
=> ()
(factors 6 2 3 4)
=> (2 3)
then you can answer your original question by simply using empty?:
(empty? (factors 5 2 3 4))
=> true
(empty? (factors 6 2 3 4))
=> false