13

The only thing I've found that works is

(eval `(vector ,@(mapcar #'1+ [1 2 3 4])))
=> [2 3 4 5]

but that seems far too complicated to be the 'right' way.

17

Use cl-map, instead:

(cl-map 'vector #'1+ [1 2 3 4])

A little extra background: cl-map is the Common Lisp map function that generalizes to sequence types:

(cl-map 'vector #'1+ '[1 2 3 4]) ;; ==> [2 3 4 5]
(cl-map 'list   #'1+ '(1 2 3 4)) ;; ==> (2 3 4 5)
(cl-map 'string #'upcase "abc")  ;; ==> "ABC"

It can also convert between sequence types (eg, here, the input is a list and the output is a vector):

(cl-map 'vector #'1+ '(1 2 3 4)) ;; ==> [2 3 4 5]
  • 1
    18 seconds the 'winner' :) Don't the cl libraries give compiler warnings, though? (Mostly because the FSF is obnoxious?) – Sean Allred Nov 1 '14 at 14:51
  • FWIW, I think the byte compilation problems were related to the old cl library rather than the rejiggered cl-lib library. I don't for example, get any warnings when I (defun fnx () (cl-map 'vector #'1+ '[1 2 3 4])) and then (byte-compile 'fnx). – Dan Nov 1 '14 at 15:01
  • 2
    Even if you use the compatibility cl-lib, I think you'll get warnings on older emacs (24.2). I wouldn't worry about it though, you have to pick your battles. – Malabarba Nov 1 '14 at 15:07
14

Since I was beat by 18 seconds, here's a simpler and safer way to do it without the cl library. It also doesn't evaluate the elements.

(apply #'vector (mapcar #'1+ [1 2 3 4])) ;; => [2 3 4 5]
  • That's also quite nice! Re: your earlier comment about older Emacs: it seems especially helpful if you have to anticipate legacy users. It seems most helpful if you only have to use it in a couple of spots, at which point you can trade off the slight inconvenience against avoiding the cl-lib dependency. – Dan Nov 1 '14 at 15:27
  • 1
    Very nifty!! I didn't think about using apply. – Sean Allred Nov 1 '14 at 22:51
  • I think (apply #'vector ...) might be ever so slightly faster, but for completeness, it can also be replaced with (vconcat ...). – Basil Nov 12 '18 at 20:03
1

The not so elegant inplace-variant for the case that the original vector is no longer needed afterwards and memory allocation is time-critical (e.g. the vector is big).

(setq x [1 2 3 4])

(cl-loop for var across-ref x do
         (setf var (1+ var)))

The result is stored in x. If you need the form to return x in the end you can add finally return x as follows:

(cl-loop for var across-ref x do
         (setf var (1+ var))
         finally return x)
0

You can use loop

(let ((v (vector 1 2 3 4)))
  (dotimes (i (length v))
    (aset v i (1+ (aref v i))))
  v)
;; => [2 3 4 5]

Sometimes you don't want to modify the original vector, you can make a copy

(let* ((v0 (vector 1 2 3 4))
       (v (copy-sequence v0)))
  (dotimes (i (length v))
    (aset v i (1+ (aref v i))))
  (list v0 v))
;; => ([1 2 3 4] [2 3 4 5])

or create a new vector from scratch

(let* ((v0 (vector 1 2 3 4))
       (v (make-vector (length v0) nil)))
  (dotimes (i (length v))
    (aset v i (1+ (aref v0 i))))
  (list v0 v))
;; => ([1 2 3 4] [2 3 4 5])

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.