The long way through Software Craftsmanship

Iterate with index in clojure

Jul 4, 2015 - 2 minute read - Comments - sampleclojurerubyiteratelanguage-comparisonprotip

Scenario: iterate a sequence (seq) with its index

The lines have an implicit line number (starting by 1, in most editors):

[1] line1
[2] line2
[3] hello

When you read it from file to a variable, it is converted to:

("line1" "line2" "hello")

This implicit line number value is not present, therefore you need to assign them one.

In ruby, you have this construct:

array = ["A", "B", "C"]
array.each_with_index {|val, index| puts "#{val} => #{index}" }

Source

In clojure, there is a similar function:

(map-indexed (fn [idx itm] [idx itm]) '(:f :o))
; ([0 "line1"] [1 "line2"] [2 "hello"])

If you want to shift the collection to the right so it starts with 1 (for the REPL):

(def lines '("line1" "line2" "hello"))
; ("line1" "line2" "hello")

(defn shift-one [lines] 
  (cons "" lines))
(def lines (shift-one lines))
lines
; ("" "line1" "line2" "hello")

(map-indexed (fn [idx itm] [idx itm])
  lines)  
; ([0 ""] [1 "line1"] [2 "line2"] [3 "hello"])

Source, especially this one

But if you only need to get the lines at certain indexes, it is also possible to get the values directly, using map on the sequence of desired indexes:

lines
; ("" "line1" "line2" "hello")

(defn get-all [lines indexes]
  (map #(nth lines %) indexes))
(get-all lines '(1 2))
; ("line1" "line2")

(get-all lines '(1 1))
; ("line1" "line1")

Note: the original source code for this post is here