Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stop iterating a sequence when a condition is met

Tags:

clojure

Other than loop .. recur, what is the best Clojure construct to use so that while traversing a sequence of sequences (sos), the processing can stop if a result is found?

Here are the details:

I have a lazy sequence returned from clojure-csv, an sos.

There is a value at a given position (index) in each sequence within the sos.

I keep looking at that position in each sequence until the value is found or the end of sos is reached.

If the value is found, I want to stop processing the sos.

The only thing I can think of is using a for with when and an into to retain the match, but the sequence processing won't stop, or use filter.

However, I believe I can use something better, but I'm stuck as to what that would be.

Thanks.

like image 714
octopusgrabbus Avatar asked Aug 08 '12 14:08

octopusgrabbus


4 Answers

I prefer take-while for such tasks and if the key is at a fixed Index nth could match for it.

(take-while #(not= (nth % index) key) sos)

user> (def sos [[1 2 3] [4 5 6] [7 8 9] [10 11 12]])
#'user/sos
user> (take-while #(not= (nth %  2) 9) sos)
([1 2 3] [4 5 6])

You could then map your processing function over the resulting sequence.

like image 192
Arthur Ulfeldt Avatar answered Oct 22 '22 05:10

Arthur Ulfeldt


How about this?

(defn find-first [pred col]
  (first (filter pred col)))

Then you can do this as an example:

(find-first #(< % 5) coll)

You should be able to make a predicate that works with a sequence of sequences.

user=> (defn find-first [pred col]
  (first (filter pred col)))
#'user/find-first
user=> (find-first #(> % 10) '(1 5 8 2 15 20 31 5 1))
15
like image 39
Kyle Avatar answered Oct 22 '22 05:10

Kyle


for with :while can be used like:

(for [s sos :while (not (= (nth s index) val))]  
     s) ;;or do something with s
like image 4
Ankur Avatar answered Oct 22 '22 06:10

Ankur


When just searching for the first occurence, I would use drop-while. Indeed, filter will process the whole sequence which is not useful. (and what if you want to use infinite sequences ?)

EDIT: Don't take this into account. Indeed, filter returns a lazy sequence.

(defn find-first
  [pred coll]
  (first (drop-while #(not (pred %)) coll))
like image 1
tomferon Avatar answered Oct 22 '22 07:10

tomferon