[英]Haskell add unique combinations of list to tuple
例如說我有一個這樣的清單
list = ["AC", "BA"]
我想將此列表的每個唯一組合添加到元組,因此結果如下所示:
[("AC", "AC"),("AC","BA"),("BA", "BA")]
其中("BA","AC")
被排除。
我的第一種方法是使用像這樣的列表理解:
ya = [(x,y) | x <- list, y <- list]
但是我無法使其正常工作,是否有任何通過使用列表推導來達到目的的結果?
我的首選解決方案使用列表理解
f :: [t] -> [(t, t)]
f list = [ (a,b) | theTail@(a:_) <- tails list , b <- theTail ]
我發現這很容易理解:首先選擇a(不確定地)后綴theTail
,從a
開頭,然后選擇(不確定地)選擇后綴的元素b
。 最終,生成了對(a,b)
,該對顯然在所需對的范圍內。
它還應該是最佳效率的:每次您需要元素時,它都是在恆定時間內生成的。
ThreeFx的答案會起作用,但是它增加了元素必須可排序的約束。 取而代之的是,您可以擺脫Prelude
和Data.List
函數,從而更有效,更通用地實現此功能:
import Data.List (tails)
permutations2 :: [a] -> [(a, a)]
permutations2 list
= concat
$ zipWith (zip . repeat) list
$ tails list
它不使用列表推導,但無需執行可能比較昂貴的比較,並且對可以通過哪種值進行任何約束都可以使用。
要查看其工作原理,請考慮如果您具有列表[1, 2, 3]
,則將具有組
[(1, 1), (1, 2), (1, 3),
(2, 2), (2, 3),
(3, 3)]
這相當於
[(1, [1, 2, 3]),
(2, [2, 3]),
(3, [3])]
因為它不包含任何額外或更少的信息。 從這個表格到期望的輸出變換為映射函數f (x, ys) = map (\\y -> (x, y)) ys
在每個元組,那么concat
一起它們。 現在,我們只需要弄清楚如何獲取這些元組的第二個元素。 很明顯,我們看到它所做的所有事情都是將連續的元素從列表的前面刪除。 幸運的是,這已經通過Data.List
的tails
函數為我們實現了。 每個元組中的第一個元素就是原始列表,因此我們知道可以使用zip
。 最初,您可以使用
> concatMap (\(x, ys) -> map (\y -> (x, y)) ys) $ zip list $ tails list
但是我個人更喜歡zip
,所以我將內部函數變成了一個不需要使用lambda的函數:
> concatMap (\(x, ys) -> zip (repeat x) ys) $ zip list $ tails list
而且由於我更喜歡zipWith f
不是map (uncurry f) . zip
map (uncurry f) . zip
,我會把它變成
> concat $ zipWith (\x ys -> zip (repeat x) ys) list $ tails list
現在,我們可以進一步減少:
> concat $ zipWith (\x -> zip (repeat x)) list $ tails list
> concat $ zipWith (zip . repeat) list $ tails list
感謝eta減少和功能組成。 我們可以使這個完全沒有意義
> permutations2 = concat . ap (zipWith (zip . repeat)) tails
但是我發現這很難閱讀和理解,所以我認為我會堅持使用以前的版本。
只需使用列表理解即可:
f :: (Ord a) => [a] -> [(a, a)]
f list = [ (a, b) | a <- list, b <- list, a <= b ]
由於Haskell的String
在Ord
類型類中,這意味着可以排序,因此您首先告訴Haskell獲取所有可能的組合,然后排除b
大於a
所有組合,從而刪除所有“重復”組合。
輸出示例:
> f [1,2,3,4]
[(1,1),(1,2),(1,3),(1,4),(2,2),(2,3),(2,4),(3,3),(3,4),(4,4)]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.