LocustHorde
LocustHorde

Reputation: 6399

How do I join string set into a single string with positions prepended?

Assume I have this

(def base ["one" "two" "three"])

I want to convert it to:

1. one
2. two
3. three

(aka 1. one \n2. two \n3. three)

with join, I am not sure I can append a counter before joining:

(clojure.string/join " \n" base)
=> "one \ntwo \nthree"

and with doseq or similar, plus an atom, I do get individual strings but then will have to concatenate later on, something like

(def base ["one" "two" "three"])

(def pos (atom 0))

(defn add-pos
  [base]
  (for [b base]
    (do 
      (swap! pos inc)
      (str @pos ". " b))))

(let [pos-base (add-pos base)]
  (clojure.string/join " \n" pos-base))

=> "1. one \n2. two \n3. three"

While it works, I don't know if using an atom with a for statement is he best way to do this, it doesn't look very clojure-esque.

Is there a better way to do this please?

Upvotes: 0

Views: 179

Answers (3)

Leon Grapenthin
Leon Grapenthin

Reputation: 9266

Clearly a job for interleave.

(->> (interleave (rest (range)) (repeat ". ") base (repeat " \n"))
     (apply str))

;-> "1. one \n2. two \n3. three \n"

Upvotes: 3

status203
status203

Reputation: 876

A minor alternative to schaueho's keep-indexed would be map-indexed (spotting a pattern?)

(def base ["one" "two" "three"])

(defn numbered-list [s]
  (->> s
       (map-indexed #(str (inc %1) ". " %2))
       (interpose \newline)
       (apply str)))

(numbered-list base) ; => "1. one\n2. two\n3. three"

Upvotes: 3

schaueho
schaueho

Reputation: 3504

That's a job for keep-indexed:

user> (keep-indexed #(str (inc %1) ". " %2) ["one" "two" "three"])
("1. one" "2. two" "3. three")
user> (clojure.string/join "\n"
         (keep-indexed 
            #(str (inc %1) ". " %2) 
            ["one" "two" "three"]))
"1. one\n2. two\n3. three"

Upvotes: 4

Related Questions