mangarju
mangarju

Reputation: 13

Is there a way to aref and setf several elements of an array?

I am interested in numerical analysis and have recently began a love affair with Common LISP. I have found my thought processeses strongly influenced by years of more imperative style programming, so I am on a quest to develop a more lispy approach. A common theme for those on the LISP path, I presume.

Anyway, reading through CLTL2 it is stated that vectors can be accessed in constant time, whereas accessing a list is done in linear time (sec. 2.5.1). One can then (setf (apply #'aref *some-vector* idx) new-value) to set one place of a vector. My two-part question is:

a. Is there a way to get several values of an array by giving a list indices, without having to loop through the list? E.g., something akin to a correct version of (map 'array #'aref *some-array* idx-list).

b. Is there a way to set the values of some elements of an array in the same spirit as above? It would be ideal to be able to apply a function (via an adequately defined map, or to reduce it, etc.) to a list of values extracted from arrays for, say, sampling and interpolation.

I would also appreciate any comments regarding array operations in general and numerical computing in particular (pointers to a tutorial or book, some mailing list, common pitfalls, when to use lists or other data structures instead, etc.).

Cheers.

Upvotes: 1

Views: 598

Answers (3)

finnw
finnw

Reputation: 48659

I'm not sure why you want to avoid looping, since a function like MAP must loop anyway.

But you can use MAP, in combination with a function that creates a cyclic list, e.g.

(defun cycle (x)
   (let ((result (list x)))
      (setf (cdr result) result)
    result))

(defun multiple-aref (array indices)
   (map 'vector #'aref (cycle array) indices))

(multiple-aref '#(a b c d e f g) '(1 3 5))

=> #(B D F)

(cycle array) creates the infinite list (array array array array ...). But MAP still works because it only examines an many elements as there are in the shortest list it is given (in this case '(1 2 3)).

Upvotes: 0

Frank Zalkow
Frank Zalkow

Reputation: 3930

a.

You can map to get to get the values by index like this:

(map 'vector #'(lambda (idx) (aref *some-array* idx)) idx-list)

Note that this works only for one-dimensional arrays. A more-than-one-dimensional version would look like this:

(map 'vector #'(lambda (idx) (apply #'aref *some-array* idx)) idx-list)

Upvotes: 2

Lars Brinkhoff
Lars Brinkhoff

Reputation: 14335

b. You can assign several consecutive values at once:

(setf (subseq vector start end) values)

Upvotes: 3

Related Questions