Reputation: 832
First of All, I have a Mysql table like this:
create table t (id int(11) PRIMARY KEY unsigned NOT NULL AUTO_INCREMENT, name varchar(20), age int(10));
I define a funtion that will create a row in t:
(require '[honeysql.core :as sql])
(defn do-something []
(sql/query {:insert-into :t
:values [{:name "name1" :age 10}]})
(> 3 (rand-int 5)))
And now I want to run this function until it return true but at most N times.
This take-times
code is wrong because repeat will eval the do-something
function one time and then structure the lazy sequence.
(defn take-times []
(some true? (repeat 5 (do-something))))
This take-times2
will eval the do-something
5 times no matter what the do-something
return.
(defn take-times2 []
(some true? (for [i (range 5)]
(do-something))))
What should I do if i do not use recursion function and macro?
Upvotes: 3
Views: 194
Reputation: 6073
This should work:
(->> (repeatedly do-something)
(take 5)
(some true?))
Update (04.11.2014):
Since repeatedly
actually allows for an optional length parameter, this is also fine:
(some true? (repeatedly 5 do-something))
Example
(defn do-something
[]
;; 20% chance of true
(let [ret (rand-nth [true false false false false])]
(prn 'hello ret)
ret))
(defn run
[]
(->> (repeatedly do-something)
(take 5)
(some true?)))
(run)
;; hello false
;; hello false
;; hello true
;; => true
(run)
;; hello false
;; hello false
;; hello false
;; hello false
;; hello false
;; => nil
Upvotes: 5
Reputation: 1395
The reduce function has the reduced option to stop processing a sequence based on a user defined criteria.
Using the random sequence of true and false
(defn rand-seq [] (repeatedly #(rand-nth [true false false false false])))
Use reduce to build a vector until either a true is found or a maximum number of false values has been reached.
(defn at-most-or-true [s max-false]
(reduce (fn [acc v]
(if (and (not v) (< (count acc) max-false))
(conj acc v)
(reduced acc)))
[] s))
This can be tested by calling
(at-most-or-true (rand-seq) 5)
Upvotes: 0