¿Cómo puedo mapear sobre un vector y obtener un vector?


15

Lo único que he encontrado que funciona es

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

pero que parece ahora demasiado complicado para ser la forma 'correcta'.

Respuestas:


19

Use cl-map, en cambio:

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

Un poco de información adicional: cl-mapes la función Common Lispmap que se generaliza a los tipos de secuencia:

(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"

También puede convertir entre tipos de secuencia (por ejemplo, aquí, la entrada es una lista y la salida es un vector):

(cl-map 'vector #'1+ '(1 2 3 4)) ;; ==> [2 3 4 5]

1
18 segundos el 'ganador' :) Sin clembargo, ¿las bibliotecas no dan advertencias al compilador? (¿Principalmente porque la FSF es desagradable?)
Sean Allred el

1
FWIW, creo que los problemas de compilación de bytes estaban relacionados con la clbiblioteca anterior en lugar de la cl-libbiblioteca rejigger . Por ejemplo, no recibo ninguna advertencia cuando (defun fnx () (cl-map 'vector #'1+ '[1 2 3 4]))y luego (byte-compile 'fnx).
Dan

2
Incluso si usa la compatibilidad cl-lib, creo que recibirá advertencias en emacs anteriores (24.2). Sin embargo, no me preocuparía, tienes que elegir tus batallas.
Malabarba

16

Como me vencieron 18 segundos, aquí hay una manera más simple y segura de hacerlo sin la biblioteca cl. Tampoco evalúa los elementos.

(apply #'vector (mapcar #'1+ [1 2 3 4])) ;; => [2 3 4 5]

¡Eso también es bastante bueno! Re: su comentario anterior sobre Emacs anteriores: parece especialmente útil si tiene que anticiparse a los usuarios heredados. Parece más útil si solo tiene que usarlo en un par de lugares, momento en el que puede compensar el pequeño inconveniente de evitar la cl-libdependencia.
Dan

1
Muy ingenioso !! No pensé en usar apply.
Sean Allred

Creo que (apply #'vector ...)podría ser un poco más rápido, pero para completar, también se puede reemplazar (vconcat ...).
Basil

1

La variante in situ no tan elegante para el caso de que el vector original ya no sea necesario después y la asignación de memoria es crítica en el tiempo (por ejemplo, el vector es grande).

(setq x [1 2 3 4])

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

El resultado se almacena en x. Si necesita que el formulario regrese xal final, puede agregar finally return xlo siguiente:

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

1

Para completar, usando seq:

(require 'seq)
(seq-into (seq-map #'1+ [1 2 3 4]) 'vector)

Hay una respuesta eliminada de Fólkvangr 2018-11-12 con exactamente la misma seq-intolínea. El usuario ha eliminado su respuesta por la siguiente razón: "Mi solución es menos relevante porque la biblioteca seq utiliza las extensiones subyacentes de Common Lisp. - Fólkvangr 16 de mayo a las 8:53"
Tobias

@Tobias, creo que no estoy de acuerdo con esa lógica. De todos modos, todo terminará usando vconcat o vector, pero los diferentes paradigmas de interfaz son útiles para tener en el registro.
Sean Allred

No hay problema. Acabo de ver la respuesta eliminada de Fólkvangr (casi) coincidente con la tuya y quería notificarte. Por alguna razón, ver las respuestas eliminadas requiere 10000 rep :-(.
Tobias

@Tobias, sí, nunca entendí por qué esos privilegios eran específicos del sitio :-)
Sean Allred

0

Puedes usar loop

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

A veces no desea modificar el vector original, puede hacer una copia

(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])

o crear un nuevo vector desde cero

(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])
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.