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.