Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure: Test a sequence for a running property

Tags:

clojure

Suppose you want to test a Clojure sequence for a property that is defined only in terms of contiguous elements. For example, monotonicity.

(defn monotonic?
    [sequence]
    (every? #(<= (first %) (second %))
            (partition 2 1 sequence)))

But I actually want to do this for a number of different properties. I could copy this for each, or I could abstract:

(defn sequence-has-property?
    [f sequ]
    (every? #(apply f %)
            (partition 2 1 sequ)))

If I want to abstract out the number of previous terms on which a test is dependent (for example, so that #(= %3 (+ % %2)) could test for a generalized Fibonacci pattern), I could write:

(defn sequence-has-property? [f sequ n] (every? #(apply f %) (partition n 1 sequ)))

Question: Is there a better (faster/more idiomatic) way?

like image 683
galdre Avatar asked Dec 01 '25 10:12

galdre


1 Answers

Taken from linked question of OP:

Just make the predicate function itself take variadic arguments, and have it do the partitioning / recurring. Your monotonic? for instance already exists in core, and is called <=

(<= 1 2 4 5)
=> true
(<= 1 2 1 5)
=> false

Here's the source for the 1, 2 and variadic arg versions:

(source <=)
(defn <=
  "Returns non-nil if nums are in monotonically non-decreasing order,
  otherwise false."
  {:inline (fn [x y] `(. clojure.lang.Numbers (lte ~x ~y)))
   :inline-arities #{2}
   :added "1.0"}
  ([x] true)
  ([x y] (. clojure.lang.Numbers (lte x y)))
  ([x y & more]
   (if (<= x y)
     (if (next more)
       (recur y (first more) (next more))
       (<= y (first more)))
     false)))

You can make a fib? work the same way, have it take variadic arguments and recur over triples:

(defn fib?
  [a b & [c & r]]
  (if (= c (+ a b))
    (if r
      (recur b c r)
      true)
    false))

(fib? 0 1 1)
=> true

(fib? 2 3 5 8 13)
=> true
like image 183
NielsK Avatar answered Dec 04 '25 15:12

NielsK



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!