select
@Carlの回答に基づいて、select :: [a] -> [(a, [a])]
関数を実装しました。タプル(a, [a])
の最初の部分はリストの要素であり、タプルの2番目の部分はその要素を除くリストのすべての要素です。
select :: [a] -> [(a, [a])]
select [] = []
select (x:xs) = select' x [] xs
where
select' x left [] = [(x, left)]
select' x left right@(r:rs) = (x, left++right) : select' r (x:left) rs
select
しかし、Haskell Libraries メーリング リストで、さらに簡単な実装を見つけました。
select :: [a] -> [(a,[a])]
select [] = []
select (x:xs) = (x,xs) : [(y,x:ys) | (y,ys) <- select xs]
これら 3 つは同等であることに注意してください (second
は の関数ですControl.Arrow
)。
[(y,x:ys) | (y,ys) <- select xs]
map (\(y,ys) -> (y,x:ys)) (select2 xs)
map (second (x:)) (select2 xs)
使用方法の例を次に示しますselect
。
select [1,2,3] -- [(1,[2,3]),(2,[1,3]),(3,[2,1])]
を実装する前に、Hayooselect
で型を持つ関数を見つけようとしました。さまざまなライブラリにいくつかの実装があります。[a] -> [(a, [a])]
permutations
問題は、すべての順列select
を生成するのに十分ではないということです。タイプが である を使用して、各タプルの両方の部分を cons できますが、すべてではなく一部の順列しか得られません。uncurry (:)
(a, [a]) -> [a]
map (uncurry (:)) (select [1,2,3]) -- [[1,2,3],[2,1,3],[3,2,1]]
select [1,2,3]
リストを作成する理由は明らかですが[(1,[2,3]),(2,[1,3]),(3,[2,1])]
、各タプルの 2 番目の部分でもあるサブリストを並べ替える必要があります。言い換えると、 がある場合は(1, [2,3])
、 も追加する必要があり(1, [3,2])
ます。
リストのすべての順列を見つけるための完全なコードは次のとおりです。
select :: [a] -> [(a,[a])]
select [] = []
select (x:xs) = (x,xs) : map (\(y,ys) -> (y,x:ys)) (select xs)
permutations :: [a] -> [[a]]
permutations [] = [[]]
permutations xs = [cons s2 | s <- select2 xs, s2 <- subpermutations s]
where cons :: (a, [a]) -> [a]
cons = uncurry (:)
subpermutations :: (a, [a]) -> [(a, [a])]
subpermutations (x,xs) = map (\e -> (x, e)) $ permutations xs
関数の順列の順序は とは異なることに注意してくださいData.List.permutations
。私たちの関数には辞書式の順序がありますが、そうでData.List.permutations
はありません:
permutations [1,2,3] -- [[1,2,3],[2,1,3],[2,3,1],[1,3,2],[3,1,2],[3,2,1]]
Data.List.permutations [1,2,3] -- [[1,2,3],[2,1,3],[3,2,1],[2,3,1],[3,1,2],[1,3,2]]
permutations
最後に、関数をさらに単純化すると、 Rosetta Codeにある実装が得られます。
select :: [a] -> [(a,[a])]
select [] = []
select (x:xs) = (x,xs) : map (\(y,ys) -> (y,x:ys)) (select xs)
permutations :: [a] -> [[a]]
permutations [] = [[]]
permutations xs = [ y:zs | (y,ys) <- select xs, zs <- permutations ys]
また、挿入ベースのアプローチを使用する Rosetta Code の実装には、 と同じ (非辞書式) 順序があることに注意してくださいData.List.permutations
。
ノート
FWIWscc :: [(a, [a])] -> [[a]]
、パッケージの関数があり、グラフの強く接続されたコンポーネントuhc-util
を見つけます。タプルの最初の部分は頂点で、2 番目の部分はすべての頂点であり、頂点からのエッジがそこに向かいます。IOW、グラフになります。1 --> 2 --> 3
[(1, [2]), (2, [3])]
scc [(1,[2,3,4]),(2,[1,3,4]),(3,[2,1,4]),(4,[3,2,1])] -- [[3,4], [1,2]]