Skip to content

Instantly share code, notes, and snippets.

Last active July 20, 2020 15:15
Show Gist options
  • Save ericnormand/99c57ed413cc280ce72d6094868fef75 to your computer and use it in GitHub Desktop.
Save ericnormand/99c57ed413cc280ce72d6094868fef75 to your computer and use it in GitHub Desktop.

indices of a value

Let's say you've got a sequence, [:a 1 :d :f :r 4 :d] and you want to find all of the indices where :d is. That would be (2 6). Your task is to write that function:

(indices-of :d [:a 1 :d :f :r 4 :d])  ;=> (2 6)

Thanks to this site for the challenge idea where it is considered Medium level in Python.

Email submissions to before July 19, 2020. You can discuss the submissions in the comments below.

(ns tst.demo.core
(:use tupelo.core tupelo.test))
(defn indices-of
[tgt items]
(let [indexed-items (indexed items)
keepers (filterv (fn [[ii vv]]
(= vv tgt))
keep-idx (mapv first keepers)]
(is= [2 6] (indices-of :d [:a 1 :d :f :r 4 :d])))
(defn indices-of
[x xs]
(filter some? (map #(when (= x (get xs %)) %)
(range (count xs)))))
(defn indices-of [x col] (filter identity (map-indexed #(when (= %2 x) %1) col)))
(defn indices-of [needle haystack]
(let [idx (atom 0)]
(fn [indices val]
(swap! idx inc)
(if (= val needle)
(cons (dec @idx) indices)
(indices-of :d [:a 1 :d :f :r 4 :d]) ; => (2 6)
;; Hi newsletter readers,
;; I know it's not part of the challenge, but keep-indexed returns a transducer
;; when called with a single argument, so this implementation of indices-of can
;; likewise return a transducer almost for free. However, now I have two lines of
;; duplication. Can you think of an elegant way to avoid the duplication?
;; Using an & parameter allows for any arity greater than 1, makes the signature
;; unclear and the implentation overly complex.
;; Extracting the function passed to keep-indexed only partially removes
;; duplication and makes the overall implementation less consise.
;; My conclusion is that in this particular case, given the alternatives,
;; considering the duplication is very local and small, and provided adequate
;; tests, the duplication is fine.
(defn indices-of
"Returns a lazy sequence of all indices in (seq `coll`) at which `x` was found.
Returns a stateful transducer when no collection is provided."
(keep-indexed (fn [idx el]
(when (= x el) idx))))
([x coll]
(keep-indexed (fn [idx el]
(when (= x el) idx))
(assert (= [] (indices-of :d [])))
(assert (= [] (indices-of :d [0 1 2])))
(assert (= [0] (indices-of :d [:d])))
(assert (= [2 6] (indices-of :d [:a 1 :d :f :r 5 :d])))
(defn indices-of [k c]
(keep-indexed #(when (= %2 k) %1) c))
(defn indices-of [k c]
(for [[i v] (map-indexed vector c) :when (= v k)] i))
(defn indices-of [k c]
(->> (map list (range) c) (filter #(= k (second %))) (map first)))
(defn indices-of [ik c]
(reduce (fn [a [k v]] (if (= ik v) (conj a k) a)) '() (map-indexed vector c)))
(defn indices-of [k c]
(loop [i 0 acc '() v c]
(if (nil? v)
(recur (inc i) (if (= (first v) k) (conj acc i) acc) (next v)))))
(defn indices-of [item coll]
(keep-indexed (fn [idx val] (when (= item val) idx)) coll))
(defn indices-of [x ys]
(keep-indexed #(when (= x %2) %1) ys))
Copy link

miner commented Jul 20, 2020

I like Jeroen's idea of adding the transducer version. He asked about the code duplication. My recommendation would be to make the two-arg arity call the transducer. sequence maintains the laziness.

(defn indices-of
  ([x]   (keep-indexed (fn [idx el] (when (= x el) idx))))
  ([x coll]   (sequence (indices-of x) coll)))

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