2013-07-30 18 views
6

Common Lispは、多くの書式設定ディレクティブをサポートしています。しかし、私は自分の問題のための便利な指示を見つけることができませんでした。基本的に、私は数字のグリッドを印刷したいと思います。うまくリストに、次の作品を使用してCommon Lispでベクトルを反復処理するフォーマットディレクティブはありますか?

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

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

を私はベクトルを反復するために類似した構造を見つけることができませんでした。 CLtL2 states clearly that~{...~}は、リストを引数として想定しています。とにかくベクトルを使用しようとしましたが、私のClispは間違った引数型について正しく叫んでいました。回避策として、私のベクトルを全能の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 

これはうまくいきますが、不器用な解決策として私を襲ってしまいます。私はむしろ、formatのためにだけ一時的なリストのトンを作成したいと思います。ベクトルを直接反復する方法はありますか?

好奇心で、formatがシーケンスをサポートすべきではない理由はありますか?

+0

いつも '(format t"〜/ func-name/"何か")で自分自身を追加することができます –

答えて

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 

あなたはより多くの引数を(彼らはカンマで区切ります)を追加することもできますし、また何らかの形でコロンとアンパサンドを扱うことができます。 Svanteのアドバイスに従い

は、ここで、この機能の多少変更されたバージョンですが、それはまた次のようにコロンとアンパサンドを利用:コロンは、それがprin1princ間とアットマークに変更になり、それが再帰的にネストされた配列を印刷します(それは可能性がありさらにまた、多次元配列などを印刷する洗練された...しかし、ここでは、限られた時間を持つことは、それが何であるかです:

(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

私は(ハードなデータはなく、ちょっとした経験があると思います) 1つの命令から構成され、適切なパラメータで「書込み」を使用する書式文字列は、はるかに効果的です。これは、文字列の各文字のタイトなループで発生するため、ここでは問題になりそうです。 – Svante

3
  1. 私はlist秒にvector秒に変換するためにcoerceの代わりloopを使用します。
  2. 私はではありません。を使用します。format + coercevectors;私はvectorで直接反復します。これにより、より読みやすい(より効率的な)コードが生成されます。
  3. formatがサポートされない理由は、おそらく歴史的です。vector
1

あなたはおそらくのようなものを探していますされています

(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 

しかし、これは確かに最も効率的で可読な方法ではなく、ベクター上で直接反復するので、私はsdsの答えに耳を傾けるでしょう。

関連する問題