Come posso mappare su un vettore e ottenere un vettore?


15

L'unica cosa che ho scoperto che funziona è

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

ma che sembra di gran lunga troppo complicato per essere il modo 'giusto'.

Risposte:


19

Usa cl-mapinvece:

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

Un piccolo sfondo extra: cl-mapè la funzione Common Lispmap che si generalizza ai tipi di sequenza:

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

Può anche convertire tra tipi di sequenza (ad esempio, qui l'input è un elenco e l'output è un vettore):

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

1
18 secondi il 'vincitore' :) Ma le clbiblioteche non danno avvertimenti al compilatore? (Soprattutto perché la FSF è odiosa?)
Sean Allred,

1
FWIW, penso che i problemi di compilazione dei byte fossero correlati alla vecchia cllibreria piuttosto che alla cl-liblibreria reimpostata . Ad esempio, non ricevo alcun avviso quando io (defun fnx () (cl-map 'vector #'1+ '[1 2 3 4]))e poi (byte-compile 'fnx).
Dan

2
Anche se usi la compatibilità cl-lib, penso che riceverai avvisi su emacs più vecchi (24.2). Non mi preoccuperei, però, devi scegliere le tue battaglie.
Malabarba,

16

Da quando sono stato battuto per 18 secondi, ecco un modo più semplice e sicuro per farlo senza la libreria cl. Inoltre non valuta gli elementi.

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

È anche molto carino! Ri: il tuo commento precedente su Emacs precedenti: sembra particolarmente utile se devi anticipare gli utenti legacy. Sembra molto utile se devi usarlo solo in un paio di punti, a quel punto puoi compensare il leggero inconveniente contro evitare la cl-libdipendenza.
Dan

1
Molto elegante !! Non ho pensato di usare apply.
Sean Allred,

Penso che (apply #'vector ...)potrebbe essere leggermente più veloce, ma per completezza, può anche essere sostituito (vconcat ...).
Basilio,

1

La variante sul posto non così elegante per il caso in cui il vettore originale non è più necessario in seguito e l'allocazione della memoria è critica in termini di tempo (ad esempio, il vettore è grande).

(setq x [1 2 3 4])

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

Il risultato è memorizzato in x. Se alla fine è necessario il modulo da restituire, xè possibile aggiungere finally return xcome segue:

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

1

Per completezza, usando seq:

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

C'è una risposta cancellata da Fólkvangr 2018-11-12 con la stessa identica seq-intoriga. L'utente ha eliminato la sua risposta per il seguente motivo: "La mia soluzione è meno pertinente perché la libreria seq utilizza le estensioni Common Lisp sottostanti. - Fólkvangr 16 maggio alle 8:53"
Tobias

@Tobias Immagino che non sarei d'accordo con questa logica. Tutto finirà comunque per usare vconcat o vector, ma i diversi paradigmi di interfaccia sono utili da tenere in considerazione.
Sean Allred,

Nessun problema. Ho appena visto la risposta eliminata di Fólkvangr (quasi) corrispondente alla tua e volevo avvisarti. Per qualsiasi motivo, vedere le risposte cancellate richiede 10000 rep :-(.
Tobias

@Tobias sì, non ho mai veramente capito perché quei privilegi fossero specifici del sito :-)
Sean Allred,

0

Puoi usare il 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 volte non si desidera modificare il vettore originale, è possibile effettuare 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 crea un nuovo vettore da zero

(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])
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.