Reputation: 529
Suppose I have a list of elements L
, a function g
, and a list of indices I
.
Then, how can I map the function g
only to the elements of the list L
specified by the indices I
?
For instance, if g
is the squaring function, L
is the list (1 2 3 4 5 6 7)
and I
is the set of indices (1 3 4)
, then I should obtain
(1 4 3 16 25 6 7)
, that is the list L
in which I squared the elements in positions I
.
(The first index is 0, like it is used in the nth
function)
I can do it in some way or another, but I was wondering if there is a simple way to do it.
Upvotes: 0
Views: 244
Reputation: 29958
Another option is to loop over the desired indexes to change, using assoc
to replace items in a vector:
(ns tst.demo.core
(:use tupelo.core tupelo.test) )
(defn update-idx
[data txfn idxs]
(reduce
(fn [result idx]
(let [val-orig (get result idx)
val-new (txfn val-orig)]
(assoc result idx val-new)))
(vec data) ; coerce data to vector
idxs))
(dotest
(let [plus100 (fn [x] (+ 100 x))]
(is= (update-idx (range 10) plus100 [2 3 5 7]))
[0 1 102 103 4 105 6 107 8 9]))
Upvotes: 0
Reputation: 45750
Or, without a library, you can just make use of map-indexed
:
(def I #{1 3 4})
(def L '(1 2 3 4 5 6 7))
(defn g [n] (* n n))
(map-indexed #(if (I %) (g %2) %2) L))
; or, with explicit parameters
(map-indexed (fn [i n] (if (I i) (g n) n)) L)
; Both produce a lazy-list of (1 4 3 16 25 6 7)
Of course, with better names, this would be a lot more readable.
I have I
as a set here instead of a list so lookups can be done efficiently. If you have it as a list originally, you can convert it to a set using set
.
Also note, this produces a lazy-list. If you want a different structure, you can use vec
for example to force it into a vector afterward.
Upvotes: 3
Reputation: 362
I would say, you can do it with a simple map
call:
(defn g [x]
(* x x))
(def L '(1 2 3 4 5 6 7))
(def I '(1 3 4))
(map #(g (nth L %)) I)
;; => (4 16 25)
The mindset here is, for each indexes of I
, I lookup the associated value in L
and I compute g
function over it.
Upvotes: 0
Reputation: 16035
(require '[com.rpl.specter :as s])
(use '[plumbing.core])
(s/transform [s/INDEXED-VALS (fn->> first (contains? #{1 3 4})) s/LAST]
(fn [x] (* x x))
'(1 2 3 4 5 6 7))
Upvotes: 1