Bagaimana saya bisa memetakan di atas vektor dan mendapatkan vektor?

15

Satu-satunya hal yang saya temukan yang berhasil adalah

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

tapi yang tampaknya jauh terlalu rumit untuk menjadi 'benar' cara.

Sean Allred
sumber

Jawaban:

19

Gunakan cl-map, sebagai gantinya:

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

Sebuah latar belakang ekstra: cl-mapadalah Common Lisp mapfungsi yang generalizes ke urutan jenis:

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

Itu juga dapat mengkonversi antara jenis urutan (misalnya, di sini, input adalah daftar dan output adalah vektor):

(cl-map 'vector #'1+ '(1 2 3 4)) ;; ==> [2 3 4 5]
Dan
sumber
1
18 detik, 'pemenangnya' :) Namun, bukankah clperpustakaan memberi peringatan pada kompiler? (Sebagian besar karena FSF menjengkelkan?)
Sean Allred
1
FWIW, saya pikir masalah kompilasi byte terkait dengan clperpustakaan lama daripada cl-libperpustakaan rejiggered . Saya tidak misalnya, mendapatkan peringatan apa pun ketika saya (defun fnx () (cl-map 'vector #'1+ '[1 2 3 4]))lalu (byte-compile 'fnx).
Dan
2
Bahkan jika Anda menggunakan kompatibilitas cl-lib, saya pikir Anda akan mendapatkan peringatan pada emacs lama (24.2). Saya tidak akan khawatir tentang itu, Anda harus memilih pertempuran Anda.
Malabarba
16

Karena saya dikalahkan 18 detik, inilah cara yang lebih sederhana dan lebih aman untuk melakukannya tanpa pustaka cl. Itu juga tidak mengevaluasi elemen.

(apply #'vector (mapcar #'1+ [1 2 3 4])) ;; => [2 3 4 5]
Malabarba
sumber
Itu juga cukup bagus! Re: komentar Anda sebelumnya tentang Emacs yang lebih lama: sepertinya sangat membantu jika Anda harus mengantisipasi pengguna lama. Tampaknya paling membantu jika Anda hanya perlu menggunakannya di beberapa tempat, pada titik mana Anda dapat menukar sedikit ketidaknyamanan dengan menghindari cl-libketergantungan.
Dan
1
Sangat bagus !! Saya tidak berpikir untuk menggunakan apply.
Sean Allred
Saya pikir (apply #'vector ...)mungkin sedikit lebih cepat, tetapi untuk kelengkapan, itu juga bisa diganti (vconcat ...).
Basil
1

Varian inplace-tidak begitu elegan untuk kasus bahwa vektor asli tidak lagi diperlukan setelah itu dan alokasi memori kritis-waktu (misalnya vektor besar).

(setq x [1 2 3 4])

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

Hasilnya disimpan di x. Jika Anda membutuhkan formulir untuk kembali xpada akhirnya Anda dapat menambahkan finally return xsebagai berikut:

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

Untuk kelengkapan, gunakan seq:

(require 'seq)
(seq-into (seq-map #'1+ [1 2 3 4]) 'vector)
Sean Allred
sumber
Ada jawaban yang dihapus dari Fólkvangr 2018-11-12 dengan seq-intobaris yang sama persis . Pengguna telah menghapus jawabannya karena alasan berikut: "Solusi saya kurang relevan karena perpustakaan seq menggunakan ekstensi Common Lisp yang mendasarinya. - Fólkvangr 16 Mei pukul 8:53"
Tobias
@Tobias kurasa aku tidak akan setuju dengan logika itu. Semuanya akan berakhir dengan menggunakan vconcat atau vektor, tetapi paradigma antarmuka yang berbeda berguna untuk dicatat.
Sean Allred
Tidak masalah. Saya baru saja melihat jawaban yang dihapus dari Fólkvangr (hampir) cocok dengan milik Anda dan ingin memberi tahu Anda. Untuk alasan apa pun melihat jawaban yang dihapus memerlukan 10.000 rep :-(.
Tobias
@Tobias ya, saya tidak pernah benar-benar mengerti mengapa hak istimewa itu khusus untuk situs :-)
Sean Allred
0

Anda bisa menggunakan loop

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

Terkadang Anda tidak ingin memodifikasi vektor asli, Anda dapat membuat salinan

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

atau buat vektor baru dari awal

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