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.