Bir vektör üzerinde nasıl harita oluşturabilirim ve vektör alabilirim?


15

İşe yaradığını bulduğum tek şey

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

ama görünüyor uzakta çok 'doğru' yol olarak karmaşık.

Yanıtlar:


19

Kullanım cl-mapyerine,:

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

Biraz ekstra arka plan: dizi türlerine genelleme cl-mapyapan Ortak Lisp mapişlevidir :

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

Ayrıca dizi türleri arasında dönüştürme yapabilir (örn. Burada giriş bir listedir ve çıkış bir vektördür):

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

1
18 saniye 'kazanan' :) clKütüphaneler derleyici uyarısı vermiyor mu? (Çoğunlukla FSF iğrenç olduğu için mi?)
Sean Allred

1
FWIW, bayt derleme problemlerinin yeniden clyapılandırılmış cl-libkütüphane yerine eski kütüphaneyle ilgili olduğunu düşünüyorum . Mesela ben (defun fnx () (cl-map 'vector #'1+ '[1 2 3 4]))ve sonra hiçbir uyarı almıyorum (byte-compile 'fnx).
Dan

2
Uyumluluk cl-lib'i kullansanız bile, eski emaclar hakkında uyarılar alacağınızı düşünüyorum (24.2). Bununla ilgili endişelenmezdim, savaşlarını seçmelisin.
Malabarba

16

18 saniye boyunca dövüldüğüm için, cl kütüphanesi olmadan bunu yapmanın daha basit ve daha güvenli bir yolu var. Ayrıca unsurları değerlendirmez.

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

Bu da oldukça hoş! Re: eski Emacs hakkında daha önce yaptığınız yorum: eski kullanıcıları öngörmeniz özellikle yararlı görünüyor. Sadece birkaç noktada kullanmak zorunda kalırsanız en yararlı görünüyor, bu noktada cl-libbağımlılıktan kaçınmaya karşı hafif rahatsızlığı takas edebilirsiniz .
Dan

1
Çok şık !! Kullanmayı düşünmedim apply.
Sean Allred

Bence (apply #'vector ...)her zamankinden biraz daha hızlı olabilir, ancak tamlık için de değiştirilebilir (vconcat ...).
Fesleğen

1

Orijinal vektörün artık sonradan ihtiyaç duyulmadığı ve bellek tahsisinin zaman açısından kritik olduğu durumlarda (örn. Vektör büyüktür) durum için o kadar şık olmayan yer-varyantı.

(setq x [1 2 3 4])

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

Sonuç, içinde saklanır x. xSonunda dönmek için forma ihtiyacınız varsa finally return xaşağıdaki gibi ekleyebilirsiniz :

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

1

Tamlık için seq:

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

Silinmiş bir yanıtı var Fólkvangr tam aynı olan 2018/11/12 seq-intohattı. Kullanıcı şu nedenden dolayı cevabını sildi: "Seq kütüphanesi temel Common Lisp uzantılarını kullandığından çözümüm daha az alakalı. - Fólkvangr 16 Mayıs, 8:53"
Tobias

@ Tobias Sanırım bu mantığa katılmıyorum. Her şey zaten vconcat veya vector kullanarak sona erecek, ancak farklı arayüz paradigmaları kayıtta olmak için yararlıdır.
Sean Allred

Sorun değil. Ben sadece Fólkvangr (neredeyse) seninkine eşleşen silinen cevabı gördüm ve size bildirmek istedim. Herhangi bir nedenle silinen cevapları görmek 10000 tekrar gerektirir :-(.
Tobias

@Tobias evet, bu ayrıcalıkların neden siteye özel olduğunu hiç anlamadım :-)
Sean Allred

0

Döngüyü kullanabilirsiniz

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

Bazen orijinal vektörü değiştirmek istemezsiniz, bir kopyasını yapabilirsiniz

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

veya sıfırdan yeni bir vektör oluşturun

(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])
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.