順列の列挙

順列を列挙する関数が野暮用で必要になったが、すぐに書けなかったので書き方を調べた。要素を木構造にして深さ優先探索(DFS)で書けば良いらしい。簡単だね!

(defun permutation (args &optional num head res)
  (labels ((iter (args num head res)
             (if (and (plusp num) args)
                 (let (l)
                   (dotimes (i (length args) (apply 'nconc (nreverse l)))
                     (push (iter (nconc (subseq args 0 i) (subseq args (1+ i))) (1- num)
                                 (append head (list (elt args i))) res) l)))
               (nconc res (list head)))))
    (iter args (or num (length args)) nil nil)))

; N<5に対して実行するとき 6!=720, 7!=5040 8!=40320, 9!=362880 に注意しよう。
*(permutation '(1 2 3))
((1 2 3) (1 3 2) (2 1 3) (2 3 1) (3 1 2) (3 2 1))

*(permutation '(1 2 3 4) 2)
((1 2) (1 3) (1 4) (2 1) (2 3) (2 4) (3 1) (3 2) (3 4) (4 1) (4 2) (4 3))

おまけ

組み合わせの列挙。ほぼ同じ形で、前に登場した要素を使わなければ良いだけ。

(defun combination (args &optional num head res)
  (labels ((iter (args num head res)
             (if (and (plusp num) args)
                 (let (l)
                   (dotimes (i (- (length args) num -1) (apply 'nconc (nreverse l)))
                     (push (iter (subseq args (1+ i)) (1- num)
                                 (append head (list (elt args i))) res) l)))
               (nconc res (list head)))))
    (iter args (or num (length args)) nil nil)))

*(combination '(1 2 3 4 5) 2)
((1 2) (1 3) (1 4) (1 5) (2 3) (2 4) (2 5) (3 4) (3 5) (4 5))

参考:


ActionScript http://www.memorycraft.jp/2008/04/post-2.html


C 順列を列挙する - 自明でない日記


C#で順列(Permutation)と組み合わせ(Combination)をすべて列挙してみよう - Bug Catharsis


C++ 順列の生成方法を教えてください。


順列列挙 - Qiita


Haskell http://www.sampou.org/cgi-bin/haskell.cgi?Programming%3a%b6%cc%bc%ea%c8%a2


エクセルで順列の列挙 - オフィス系ソフト 解決済み| 【OKWAVE】


順列の列挙の方法 -順列の列挙の方法といっても辞書式順序のやつではあ- 数学 | 教えて!goo


C# http://nekoaruki.com/csharp/combination-permutatio