Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@ericnormand
Last active July 20, 2020 15:15
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 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 eric@purelyfunctional.tv 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))
indexed-items)
keep-idx (mapv first keepers)]
keep-idx))
(dotest
(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)]
(reverse
(reduce
(fn [indices val]
(swap! idx inc)
(if (= val needle)
(cons (dec @idx) indices)
indices))
'()
haystack))))
(indices-of :d [:a 1 :d :f :r 4 :d]) ; => (2 6)
;; Hi pf.tv 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."
([x]
(keep-indexed (fn [idx el]
(when (= x el) idx))))
([x coll]
(keep-indexed (fn [idx el]
(when (= x el) idx))
coll)))
(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)
acc
(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))
@ninjure
Copy link

ninjure commented Jul 13, 2020

(defn indices-of [item coll]
  (keep-indexed (fn [idx val] (when (= item val) idx)) coll))

@zugnush
Copy link

zugnush commented Jul 14, 2020

(defn indicies-of
 [x col]
  (->> col
       (map-indexed (fn [idx item] [idx (= x item)]))
       (filter second)
       (map first)))

@JonathanHarford
Copy link

I discovered keep-indexed while trying to make my solution conciser. Which was nice.

(Excepting variable names, my solution is exactly @ninjure's.)

@miner
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