Reputation: 828
I have a vector that looks like:
[ "1" "2" "3" "4" ]
I wish to write a function returns the vector to:
[ 1 "2" 3 4 ]
; Note that the second element is still a string
Note that nothing is changed, an entirely new vector is returned. What is the simplest way to do this in clojure?
Upvotes: 2
Views: 295
Reputation: 29958
Here is how I would do it. Note that the index is zero-based:
(defn map-not-nth
"Transform all elements of coll except the one corresponding to idx (zero-based)."
[func coll idx]
{:pre [ (<= 0 idx (count coll)) ]
:post [ (= (count %) (count coll))
(= (nth coll idx) (nth % idx) ) ] }
(let [coll-tx (map func coll) ; transform all data
result (flatten [ (take idx coll-tx) ; [0..idx-1]
(nth coll idx) ; idx
(drop (inc idx) coll-tx) ; [idx+1..N-1]
] ) ]
result ))
(def xx [ 0 1 2 3 4 ] )
(prn (map-not-nth str xx 0))
(prn (map-not-nth str xx 1))
(prn (map-not-nth str xx 2))
(prn (map-not-nth str xx 3))
(prn (map-not-nth str xx 4))
Result is:
user=> (prn (map-not-nth str xx 0))
(0 "1" "2" "3" "4")
user=> (prn (map-not-nth str xx 1))
("0" 1 "2" "3" "4")
user=> (prn (map-not-nth str xx 2))
("0" "1" 2 "3" "4")
user=> (prn (map-not-nth str xx 3))
("0" "1" "2" 3 "4")
user=> (prn (map-not-nth str xx 4))
("0" "1" "2" "3" 4)
Upvotes: 1
Reputation: 91554
map-indexed is a decent choice. call a function you pass with the value of one of the items form your input and the index where it was found (index first). that function can choose to produce a new value or return the existing one.
user> (map-indexed (fn [i v]
(if-not (= 1 i)
(Integer/parseInt v)
v))
[ "1" "2" "3" "4"])
(1 "2" 3 4)
When the if
returns v it is the exact same value in the resulting map so you keep the benefits of structural sharing in the parts you choose to keep. If you want the output to be kept as a vector then you can use mapv and pass the index sequence your self.
user> (mapv (fn [i v]
(if-not (= 1 i)
(Integer/parseInt v)
v))
(range)
[ "1" "2" "3" "4"])
[1 "2" 3 4]
there are many ways to write this
Upvotes: 5