Wie kann ich einen Vektor abbilden und einen Vektor erhalten?

15

Das einzige, was ich gefunden habe, das funktioniert, ist

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

Aber das scheint viel zu kompliziert, um der richtige Weg zu sein.

Sean Allred
quelle

Antworten:

19

Verwenden Sie cl-mapstattdessen:

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

Ein kleiner zusätzlicher Hintergrund: cl-mapist die Common Lisp- mapFunktion , die sich auf Sequenztypen verallgemeinert:

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

Es kann auch zwischen Sequenztypen konvertiert werden (hier ist z. B. die Eingabe eine Liste und die Ausgabe ein Vektor):

(cl-map 'vector #'1+ '(1 2 3 4)) ;; ==> [2 3 4 5]
Dan
quelle
1
18 Sekunden der 'Gewinner' :) clGeben die Bibliotheken jedoch keine Compiler-Warnungen aus? (Meistens, weil die FSF widerlich ist?)
Sean Allred
1
FWIW, ich denke, dass die Probleme bei clder Bytekompilierung eher mit der alten Bibliothek als mit der neu ausgelösten cl-libBibliothek zusammenhängen. Ich bekomme zum Beispiel keine Warnungen, wenn ich (defun fnx () (cl-map 'vector #'1+ '[1 2 3 4]))und dann (byte-compile 'fnx).
Dan
2
Selbst wenn Sie die Kompatibilität cl-lib verwenden, werden Sie meines Erachtens auf älteren Emacs (24.2) gewarnt. Ich würde mir aber keine Sorgen machen, du musst deine Schlachten auswählen.
Malabarba
16

Da ich 18 Sekunden hinter mir habe, ist dies eine einfachere und sicherere Möglichkeit, ohne die cl-Bibliothek vorzugehen. Die Elemente werden auch nicht bewertet.

(apply #'vector (mapcar #'1+ [1 2 3 4])) ;; => [2 3 4 5]
Malabarba
quelle
Das ist auch ganz nett! Betreff: Ihr früherer Kommentar zu älteren Emacs: Es scheint besonders hilfreich zu sein, wenn Sie ältere Benutzer antizipieren müssen. Es erscheint am hilfreichsten, wenn Sie es nur an einigen Stellen verwenden müssen. An diesem Punkt können Sie die leichten Unannehmlichkeiten gegen die Vermeidung der cl-libAbhängigkeit austauschen.
Dan
1
Sehr geschickt !! Ich habe nicht darüber nachgedacht apply.
Sean Allred
Ich denke, es ist (apply #'vector ...)vielleicht etwas schneller, aber der Vollständigkeit halber kann es auch durch ersetzt werden (vconcat ...).
Basil
1

Die nicht so elegante Inplace-Variante für den Fall, dass der ursprüngliche Vektor danach nicht mehr benötigt wird und die Speicherzuordnung zeitkritisch ist (zB der Vektor ist groß).

(setq x [1 2 3 4])

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

Das Ergebnis wird in gespeichert x. Wenn Sie das Formular benötigen, um es xam Ende zurückzugeben, können Sie finally return xFolgendes hinzufügen :

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

Der Vollständigkeit halber mit seq:

(require 'seq)
(seq-into (seq-map #'1+ [1 2 3 4]) 'vector)
Sean Allred
quelle
Es gibt eine gelöschte Antwort von Fólkvangr 2018.11.12 mit der exakt gleichen seq-intoLinie. Der Benutzer hat seine Antwort aus folgendem Grund gelöscht: "Meine Lösung ist weniger relevant, da die seq-Bibliothek die zugrunde liegenden Common Lisp-Erweiterungen verwendet. - Fólkvangr 16. Mai um 8:53"
Tobias
@Tobias Ich denke, ich würde mit dieser Logik nicht einverstanden sein. Alles wird ohnehin mit vconcat oder vector enden, aber die verschiedenen Schnittstellenparadigmen sind nützlich, um dokumentiert zu werden.
Sean Allred
Kein Problem. Ich sah gerade die gelöschte Antwort von Fólkvangr (fast) passend zu Ihrer und wollte Sie benachrichtigen. Aus welchem ​​Grund auch immer, um gelöschte Antworten zu sehen, sind 10000 Wiederholungen erforderlich :-(.
Tobias
@ Tobias ja, ich habe nie wirklich verstanden, warum diese Privilegien ortsspezifisch waren :-)
Sean Allred
0

Sie können Schleife verwenden

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

Manchmal möchten Sie den ursprünglichen Vektor nicht ändern, sondern können eine Kopie erstellen

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

oder erstellen Sie einen neuen Vektor von Grund auf neu

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