June 8, 2020

Clojure Goodness: Transforming Collection Items With Index

If we want to transform items in a collection we can use the map function. If we also want to use the index of the element in the collection in the transformation we must use the map-indexed function. We must provide a function with 2 arguments, where the first argument is the index of the element in the collection and the second argument is the element in the collection.

In the following examples we use the map-indexed function:

  (:require [clojure.test :refer [is]]))

;; map-indexed applies a function to each element
;; in a collection where the function gets the
;; index of the item in the collection and the item itself.
(is (= [[0 3] [1 20] [2 10] [3 2] [4 1]]
       (map-indexed (fn [index number] [index number]) [3 20 10 2 1])))

(defn indices
  "Return lazy sequence of indices of elements in a collection."
  (map-indexed (fn [index _] index) coll))

(is (= [0 1 2 3 4] (indices [3 20 10 2 1])))

(defn char-range
  "Function to return a range of characters from `start` to `end` (including)."
  [start end]
  (map char (range (int start) (inc (int end)))))

(def a-z (char-range \a \z)) ;; characters from a to z.

;; map-indexed returns a lazy sequence.
(is (= [[\a 0] [\b 1] [\c 2]]
       (take 3 (map-indexed (fn [index ch] [ch index]) a-z))))

;; Create map with letter keys and position in alphabet as values.
(def letters-positions (into {} (map-indexed (fn [index ch] [ch (inc index)]) a-z)))

(is (= [[\a 1] [\b 2] [\c 3]]
       (take 3 letters-positions)))

;; Find position of each letter of word "clojure".
(is (= [3 12 15 10 21 18 5]
       (reduce (fn [result value] (conj result (get letters-positions value)))

Written with Clojure 1.10.1.