Skip to content

Instantly share code, notes, and snippets.

@ihodes
Created August 10, 2010 19:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ihodes/517833 to your computer and use it in GitHub Desktop.
Save ihodes/517833 to your computer and use it in GitHub Desktop.
;; want this behavior
(defn iof
[val coll]
(lazy-seq
(loop [coll coll idx 0]
(cond
(empty? coll) '()
(= val (first coll)) (cons idx (recur val (rest coll) (inc idx)))
:else (recur val (rest coll) (inc idx))))))
;; works, but kind of ugly
(defn iof-2
[val coll]
((fn f [coll idx]
(lazy-seq (cond
(empty? coll) '()
(= val (first coll)) (cons idx (f (rest coll) (inc idx)))
:else (f (rest coll) (inc idx))))) coll 0))
;; idiomatic? (also could do arity overloading, but this is to keep from exposing the private API)
(defn- -indices-of
[val coll idx]
(lazy-seq
(cond
(empty? coll) '()
(= val (first coll)) (cons idx (-indices-of val (rest coll) (inc idx)))
:else (-indices-of val (rest coll) (inc idx)))))
(defn indices-of
"Returns a lazy-seq of indices where 'val appears in 'coll."
[val coll] (-indices-of val coll 0))
@ihodes
Copy link
Author

ihodes commented Aug 10, 2010

NB: I realize the first one doesn't work. I think it looks the nicest, though.

@drewr
Copy link

drewr commented Aug 10, 2010

One way to do it:

user> (defn indices-of [x xs] (filter identity (map-indexed #(when (= x %2) %1) xs)))
#'user/indices-of
user> (indices-of 'foo '[foo bar baz foo])
(0 3)

@ihodes
Copy link
Author

ihodes commented Aug 10, 2010

Totally forgot about map-indexed–that would be the most natural way to do this. Thanks! Regardless, I'm curious about the way to do this if map-indexed didn't exist.

@drewr
Copy link

drewr commented Aug 10, 2010

Variation on the same theme then:

(defn indices-of [x xs]
  (let [f (fn f [idx y ys]
              (lazy-seq
               (when (seq ys)
                 (cons (and (= y (first ys)) idx)
                       (f (inc idx) y (rest ys))))))]
    (filter identity (f 0 x xs))))

user> (indices-of 'foo '[bar foo bar foo bar])
(1 3)

@ihodes
Copy link
Author

ihodes commented Aug 10, 2010

Ah, interesting. Similar to my iof-2, but with a clarifying let block.

Perhaps the below would be idiomatic? I'm averse to using more seq xs then necessary, if empty? works.

(defn iof-2
  [val coll]
  (letfn [(f [coll idx]
             (lazy-seq (cond
                (empty? coll) '()
                (= val (first coll)) (cons idx (f (rest coll) (inc idx)))
                :else (f (rest coll) (inc idx)))))
    (f col 0)))  

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment