Làm thế nào tôi có thể ánh xạ qua một vectơ và có được một vectơ?


15

Điều duy nhất tôi thấy rằng hoạt động là

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

nhưng điều đó dường như xa quá phức tạp để có cách 'đúng'.

Câu trả lời:


19

Sử dụng cl-map, thay vào đó:

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

Thêm một chút nền tảng: cl-maphàm Lispmap chung để khái quát các loại trình tự:

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

Nó cũng có thể chuyển đổi giữa các loại trình tự (ví dụ, ở đây, đầu vào là một danh sách và đầu ra là một vectơ):

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

1
18 giây, 'người chiến thắng' :) clTuy nhiên, các thư viện không đưa ra cảnh báo về trình biên dịch? (Chủ yếu là vì FSF đáng ghét?)
Sean Allred

1
FWIW, tôi nghĩ rằng các vấn đề biên dịch byte có liên quan đến clthư viện cũ hơn là cl-libthư viện được đánh giá lại . Tôi không ví dụ, nhận được bất kỳ cảnh báo khi tôi (defun fnx () (cl-map 'vector #'1+ '[1 2 3 4]))và sau đó (byte-compile 'fnx).
Dân

2
Ngay cả khi bạn sử dụng cl-lib tương thích, tôi nghĩ bạn sẽ nhận được cảnh báo về các emacs cũ hơn (24.2). Tôi sẽ không lo lắng về điều đó, mặc dù vậy, bạn phải chọn các trận đánh của mình.
Malabarba

16

Vì tôi bị đánh bại 18 giây, đây là cách đơn giản và an toàn hơn để làm điều đó mà không cần thư viện cl. Nó cũng không đánh giá các yếu tố.

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

Điều đó cũng khá hay! Re: nhận xét trước đó của bạn về Emacs cũ: có vẻ đặc biệt hữu ích nếu bạn phải dự đoán người dùng cũ. Có vẻ hữu ích nhất nếu bạn chỉ phải sử dụng nó trong một vài điểm, tại thời điểm đó bạn có thể đánh đổi sự bất tiện nhỏ để tránh sự cl-libphụ thuộc.
Dân

1
Rất tiện lợi !! Tôi đã không nghĩ về việc sử dụng apply.
Sean Allred

Tôi nghĩ (apply #'vector ...)có thể nhanh hơn một chút, nhưng để hoàn thiện, nó cũng có thể được thay thế bằng (vconcat ...).
Basil

1

Biến thể inplace không thanh lịch cho trường hợp vectơ ban đầu không còn cần thiết sau đó và phân bổ bộ nhớ là thời gian quan trọng (ví dụ: vectơ là lớn).

(setq x [1 2 3 4])

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

Kết quả được lưu trữ trong x. Nếu bạn cần biểu mẫu để trả lại xcuối cùng, bạn có thể thêm finally return xnhư sau:

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

1

Để hoàn thiện, sử dụng seq:

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

Có một câu trả lời đã bị xóa từ Fólkvangr 2018-11-12 với cùng một seq-intodòng. Người dùng đã xóa câu trả lời của mình vì lý do sau: "Giải pháp của tôi ít liên quan hơn vì thư viện seq sử dụng các phần mở rộng Common Lisp cơ bản. - Fólkvangr ngày 16 tháng 5 lúc 8:53"
Tobias

@Tobias Tôi đoán tôi không đồng ý với logic đó. Mọi thứ cuối cùng sẽ sử dụng vconcat hoặc vector, nhưng các mô hình giao diện khác nhau rất hữu ích để ghi lại.
Sean Allred

Không vấn đề gì. Tôi vừa thấy câu trả lời đã bị xóa của Fólkvangr (gần như) khớp với bạn và muốn thông báo cho bạn. Vì bất kỳ lý do gì để thấy câu trả lời bị xóa cần 10000 rep :-(.
Tobias

@Tobias yeah, tôi chưa bao giờ thực sự hiểu lý do tại sao những đặc quyền đó là dành riêng cho trang web :-)
Sean Allred

0

Bạn có thể sử dụng vòng lặp

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

Đôi khi bạn không muốn sửa đổi vectơ gốc, bạn có thể tạo một bản sao

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

hoặc tạo một vectơ mới từ đầu

(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])
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.