2013-07-30 43 views
6

Lisp thông thường hỗ trợ rất nhiều chỉ thị định dạng. Tuy nhiên, tôi không thể tìm thấy một chỉ thị hữu ích cho vấn đề của tôi. Về cơ bản, tôi muốn in một mạng lưới các số.Có định dạng chỉ thị nào để lặp qua vectơ trong Common Lisp không?

Sử dụng một danh sách các công việc sau độc đáo:

(format t "~{~A|~A|~A~%~^-----~%~}" '(1 2 3 4 5 6 7 8 9)) 

1|2|3 
----- 
4|5|6 
----- 
7|8|9 
NIL 

tôi đã không thể tìm thấy một cấu trúc tương tự để lặp qua vectơ. CLtL2 states clearly that~{...~} hy vọng danh sách là đối số. Tôi đã thử bằng cách sử dụng một vector anyway, nhưng Clisp của tôi đúng kêu lên về loại đối số sai. Để giải quyết sự cố, tôi chuyển đổi vectơ của mình thành danh sách ném đi bằng cách sử dụng toàn bộ loop.

(let ((lst (loop for e across '#(1 2 3 4 5 6 7 8 9) collecting e))) 
    (format t "~{~A|~A|~A~%~^-----~%~}" lst)) 

1|2|3 
----- 
4|5|6 
----- 
7|8|9 
NIL 

Công trình này, nhưng nó đánh tôi như một giải pháp tạm thời vụng về. Tôi không muốn tạo nhiều danh sách tạm thời chỉ cho format. Có cách nào để lặp lại vectơ trực tiếp không?

Hết sức tò mò, có lý do nào không vì lý do tại sao format không hỗ trợ trình tự?

+0

Bạn luôn có thể tự thêm bằng '(định dạng t" ~/func-name/"cái gì đó)' –

Trả lời

7
(defun pprint-array (stream array 
        &optional colon amp (delimiter #\Space)) 
    (declare (ignore colon amp)) 
    (loop 
    :with first-time = t 
    :for x :across array 
    :unless first-time :do (format stream "~C" delimiter) :end 
    :do (format stream "~S" x) 
    (setf first-time nil))) 

(format t "~' :@/pprint-array/" #(1 2 3 4)) ; 1 2 3 4 

Bạn có thể thêm đối số (họ sẽ được phân cách bằng dấu phẩy), hoặc bạn cũng có thể xử lý bằng cách nào đó thư ruột kết và dấu và.

Theo lời khuyên của Svante, đây là phiên bản thay đổi của hàm này, nó cũng sử dụng dấu hai chấm và dấu và theo cách sau: dấu hai chấm làm cho nó thay đổi giữa prin1princ và at-sign làm cho nó in mảng lồng nhau đệ quy (có thể là thêm phức tạp cũng để in mảng đa chiều vv ... nhưng có thời gian hạn chế ở đây là những gì nó là:

(defun pprint-array (stream array 
        &optional colon amp 
         (delimiter #\Space) (line #\Newline)) 
    (if amp (loop 
      :with first-time = t 
      :for a :across array 
      :unless first-time 
      :do (when line (write-char line stream)) :end 
      :if (or (typep a 'array) (typep a 'vector)) 
      :do (pprint-array stream a colon amp delimiter line) 
      :else 
      :do (if colon (prin1 a stream) (princ a stream)) :end 
      :do (setf first-time nil)) 
     (loop 
     :with first-time = t 
     :for x :across array 
     :unless first-time 
     :do (when delimiter (write-char delimiter stream)) :end 
     :do (if colon (prin1 x stream) (princ x stream)) 
     (setf first-time nil)))) 
+0

Tôi tin (không có dữ liệu cứng, chỉ một số trải nghiệm ở đây và ở đó) thay vì sử dụng cuộc gọi 'định dạng ' một chuỗi định dạng bao gồm một lệnh duy nhất, sử dụng 'write' với các tham số thích hợp sẽ có hiệu suất đáng kể hơn. Điều này có thể có vấn đề ở đây, bởi vì nó xảy ra trong một vòng lặp chặt chẽ trên mỗi ký tự của một chuỗi. – Svante

3
  1. Tôi sẽ sử dụng coerce thay vì loop để chuyển đổi vector s để list s.
  2. Tôi sẽ không sử dụng format + coerce trên vectors; Tôi sẽ lặp lại trực tiếp trên số vector. Điều này sẽ tạo ra mã dễ đọc hơn (và hiệu quả hơn).
  3. Lý do cho format không hỗ trợ vector s có thể là lịch sử.
1

Bạn có lẽ đang tìm kiếm cái gì đó như:

(format t "~{~A|~A|~A~%~^-----~%~}" (coerce #(1 2 3 4 5 6 7 8 9) 
              'list)) 
1|2|3 
----- 
4|5|6 
----- 
7|8|9 
NIL 

Nhưng tôi sẽ insted lắng nghe câu trả lời của sds, vì đây chắc chắn không phải là cách hiệu quả nhất và có thể đọc được và lặp lại trên véc tơ trực tiếp.

Các vấn đề liên quan