Matteo
Matteo

Reputation: 529

Map only selected elements in a list

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

Answers (4)

Alan Thompson
Alan Thompson

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

Carcigenicate
Carcigenicate

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

Rozar Fabien
Rozar Fabien

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

akond
akond

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

Related Questions