Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I modify a portion of a vector in Clojure?

Tags:

clojure

I am wondering if I'm missing something basic involving vector manipulation. Let's say I have the following:

(def xs [9 10 11 12 13]) 
(def idx [0 2]) 
(def values [1 3])

If I want to return the vector [1 10 3 12 13] in Matlab, I would write xs(idx) = values. In Clojure, is there a primitive way of achieving this? Right now I'm using the following function:

(defn xinto [seq idx val]
  (apply assoc seq (interleave idx val)))

Thanks.

like image 709
ChrisR Avatar asked Aug 17 '11 00:08

ChrisR


3 Answers

It's a bit awkward because you've split up idx and values into two seqs, when they're conceptually a map of indexes to values. So if you'll permit me a little creative modification of your data format:

(def x [9 10 11 12 13]) 
(def changes {0 1, 2 3}) 

(defn xinto [v changes]
  (reduce (fn [acc [k v]]
            (assoc acc k v))
          v
          changes))

(xinto x changes) ;; gets the result you want

If you generate idx and values in some weird way that it's not convenient to group them together, you can group them later with (map list idx values) and then use my xinto implementation with that.

like image 78
amalloy Avatar answered Dec 07 '22 01:12

amalloy


I'd probably use reduce for this:

(reduce 
  (fn [old [i v]] (assoc old i v))
   x   
  (map vector idx values))

However, if you really want to do this a lot (Matlab-style) then I'd suggest creating some helper macros / functions to create some kind of DSL for vector manipulation.

like image 34
mikera Avatar answered Dec 06 '22 23:12

mikera


Could not find something better.

In the core sequence functions there is replace, but it works on values, not on keys. So,

(replace {9 2} x)

Would return

[2 10 11 12 13]

If you plan to do math related things in Clojure, I also propose you have a look at Incanter. It has a lot of APIs to manipulate mathematical data.

like image 31
Nicolas Modrzyk Avatar answered Dec 07 '22 00:12

Nicolas Modrzyk