Last active
August 29, 2015 14:15
-
-
Save embeepea/7839393104502294475d to your computer and use it in GitHub Desktop.
Clojure Needle Search
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defmacro if-nonneg [a b] | |
"Eval the 1st arg, and if it's nonnegative, return it without evaling the 2nd arg. | |
If the 1st arg evals to negative, eval and return the value of the 2nd arg." | |
`(let [v# ~a] (if (>= v# 0) v# ~b))) | |
(defn inc-if-nonneg [x] | |
"Return a value that is 1 more than x if x is nonnegative; otherwise return x." | |
(if (>= x 0) (inc x) x)) | |
(defn find-needle-end [n h] | |
"Find the END of the first occurrence of needle n in haystack h -- i.e. the | |
index of the position in h immediately after the last character in the first | |
occurrence of n. If n does not appear in h, return -1." | |
(cond | |
(empty? n) 0 ; empty needle found at front of haystack (also works for empty haystack) | |
(empty? h) -1 ; empty haystack contains no (nonempty) needles | |
; if this :else clause is invoked, we know that neither n nor h is empty: | |
:else (if-nonneg | |
(if (= (first n) (first h)) ; if first chars match... | |
; search for end of needle tail in haystack tail, and if found, | |
; return that position + 1 | |
(inc-if-nonneg (find-needle-end (rest n) (rest h))) | |
-1) | |
; otherwise, search for (entire) needle in haystack tail | |
(inc-if-nonneg (find-needle-end n (rest h)))))) | |
(defn clamp [x v] | |
"Clamp all negative values to v -- i.e. returns x if x >= 0, otherwise returns v." | |
(if (< x 0) v x)) | |
(defn find-needle [n h] | |
"Return the index of the (beginning of the) first occurrence of needle n | |
in haystack h. If n does not appear in h, return -1." | |
(clamp (- (find-needle-end n h) (count n)) -1)) | |
(defn run-tests [] | |
[ ;0123456789 | |
(= 0 (find-needle "ha" "hahaystack")) | |
(= 2 (find-needle "hay" "hahaystack")) | |
(= -1 (find-needle "halt" "hahaystack")) | |
(= 3 (find-needle "ayst" "hahaystack")) | |
(= 5 (find-needle "stack" "hahaystack")) | |
(= -1 (find-needle "stacky" "hahaystack")) | |
(= -1 (find-needle "acky" "hahaystack")) | |
(= 0 (find-needle "haha" "hahaystack")) | |
(= 2 (find-needle "hays" "hahaystack")) | |
(= 2 (find-needle "hayst" "hahaystack")) | |
(= -1 (find-needle "haste" "hahaystack")) | |
(= 9 (find-needle "k" "hahaystack")) | |
(= 0 (find-needle "" "hahaystack")) | |
(= 0 (find-needle "hahaystack" "hahaystack")) | |
(= -1 (find-needle "hahaystackify" "hahaystack")) | |
(= -1 (find-needle "needle" "hahaystack")) | |
(= 2 (find-needle "haystack" "hahaystack")) | |
(= 0 (find-needle "" "")) | |
(= -1 (find-needle "needle" "")) | |
]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment