2

以下のこの悲しいことを考えると、2つの範囲のみのすべてのペアを生成します-

[53]> (setq thingie '())

NIL
[54]> (loop for i in (generate-range 0 3) do 
(loop for j in (generate-range 4 6) do 
(push (list i j) thingie)))

NIL
[55]> thingie

((3 6) (3 5) (3 4) (2 6) (2 5) (2 4) (1 6) (1 5) (1 4) (0 6) (0 5) (0 4))
[56]>  

または、別の言い方をすれば、これは一種の 2 次元の個別のレイアウトを生成します。

任意の数の範囲を取るある種のペア生成コードを構築するにはどうすればよいでしょうか? (または、n 次元の個別のレイアウトを生成します)。

明らかに、1 つの解決策はdefmacro、リストのリストを取り、実行のためにn 個のループを作成する a を使用することですが、それは簡単な方法ではありません。

4

4 に答える 4

2
(defun map-cartesian (fn bags)
  (labels ((gn (x y)
             (if y (mapc (lambda (i) (gn (cons i x) (cdr y))) (car y))
                 (funcall fn x))))
    (gn nil (reverse bags))))

CL-USER> (map-cartesian #'print '((1 2) (a b c) (x y)))

(1 A X) 
(2 A X) 
(1 B X) 
(2 B X) 
(1 C X) 
(2 C X) 
(1 A Y) 
(2 A Y) 
(1 B Y) 
(2 B Y) 
(1 C Y) 
(2 C Y) 

シンタックス シュガーを好む場合は、

(defmacro do-cartesian ((item bags) &body body)
  `(map-cartesian (lambda (,item) ,@body) ,bags))

CL-USER> (do-cartesian (x '((1 2) (a b c) (x y)))
           (print x))

編集:(簡単な説明)

gn の最初のパラメーター x は、これまでに作成された部分タプルです。y は要素の残りのバッグです。関数 gn は、残りのバッグ (car y) の 1 つの各要素 i を反復処理して (cons ix) を形成することにより、部分タプルを拡張します。残りのバッグがなくなると (ifステートメントの else 分岐)、タプルが完了するので、タプルに対して提供された関数 fn を呼び出します。

于 2010-09-09T10:22:16.880 に答える
0

私にとって明らかなことは、再帰関数です。

于 2010-09-09T01:07:18.947 に答える
0

これを制御構造と考えている場合は、マクロ ルートが最適です。これをデータを生成する方法と考えている場合は、再帰関数が最適です。

于 2010-09-09T09:43:09.123 に答える