[英]How to work with 2 lists at the same time in haskell
我正在嘗試解決Haskell中有關字母的練習。 給定一個按新字母順序排列的單詞列表,請找到該新字母。
例如,給定單詞["ab","abd","abc","ba","bd","cc"]
,新的可能的字母是"abdc"
或"adbc"
。
我首先計算所有可能的字母順序
alfabet :: Eq a => [[a]] -> [[a]]
alfabet list = permutations $ nub $ concat $ list
在此之后,我認為我應該過濾掉錯誤的字母,但是我似乎無法傳遞足夠的信息。 我嘗試使用內置的filter
函數,嘗試編寫自己的排序函數,以便在按新順序對單詞進行排序時,結果列表與輸入列表相同,因此字母正確。 一切都無濟於事。
我想我最大的問題是我需要能夠同時處理兩個列表(單詞和不同的字母),並以不同的方式遍歷它們。
有任何提示或幫助嗎? 謝謝
有多種方法可以解決此問題。 建議的方法是在所有字母上生成所有可能的字母,然后過濾出與示例數據一致的字母。 首先,我將向您展示一種方法。
另一種方法是將示例數據中的信息提取為一些有關字母可以按什么順序進入的信息(數學家將此稱為部分排序),然后將其擴展為所有可能的排序。
import Data.List (permutations, nub, sort)
我將使用一種類型的代名詞Alphabet
,以更清楚這名單是潛在的字母,哪些詞,並定義基於字母表(排序byAlphabet
),並且將其擴展到適用於列表lexiographic
排序。
type Alphabet a = [a]
byAlphabet :: Eq a => Alphabet a -> a -> a -> Ordering
byAlphabet alphabet x y
| x == y = EQ
| otherwise = if y `elem` (dropWhile (/=x) alphabet) then LT else GT
lexiographic :: (a->a->Ordering) -> [a]->[a]->Ordering
lexiographic cmp [] [] = EQ
lexiographic cmp [] _ = LT
lexiographic cmp _ [] = GT
lexiographic cmp (x:xs) (y:ys) = case cmp x y of
EQ -> lexiographic cmp xs ys
x -> x
我們需要檢查給定單詞列表是否與給定數據consistentWith
:
consistentWith :: Eq a => [[a]] -> Alphabet a -> Bool
consistentWith xss alphabet = all (/=GT) $
zipWith (lexiographic $ byAlphabet alphabet) xss (tail xss)
您似乎很難在一系列潛在的字母中使用它,但是確實知道可以使用filter
:
anyOKby :: Eq a => [[a]] -> [Alphabet a] -> [Alphabet a]
anyOKby sortedWords = filter (consistentWith sortedWords)
提供略微編輯的alfabet
函數,該函數可以過濾掉alfabet
函數。
alfabet :: Eq a => [[a]] -> [Alphabet a]
alfabet list = anyOKby list $ permutations $ nub $ concat $ list
example = ["ab","abd","abc","ba","bd","cc"]
這按預期工作:
ghci> byAlphabet "abc" 'c' 'a'
GT
ghci> lexiographic (byAlphabet "abc") "ccba" "ccbc"
LT
ghci> consistentWith example "abcd"
False
ghci> consistentWith example "abdc"
True
ghci> alfabet example
["abdc","adbc"]
現在這是一種相當慢的方法,因為它會生成許多潛在的字母,然后慢慢將它們過濾掉。 第一次嘗試,我放棄了等待alfabet (sort $ words "hello there the their he and at ah eh")
。
我將使用一種數據類型來顯示哪些字符在其他字符之前,因此'a' :<: 'b'
表示'a'
必須在字母表中的'b'
之前
data CMP a = a :<: a deriving (Eq,Show)
我將使用[CMP a]
代替Maybe (CMP a)
只是因為concat
比import Data.Maybe (catMaybes)
容易,但是每對相鄰的單詞最多可以給出一個關於字母表的比較fact
。 facts
函數使用漂亮的zipWith f xs (tail xs)
技巧來使用f
從列表中的每個相鄰對中制造一件東西。
justTheFirst :: [a] -> [a]
justTheFirst [] = []
justTheFirst (a:_) = [a]
fact :: Eq a => [a] -> [a] -> [CMP a]
fact xs ys = justTheFirst . filter neq $ zipWith (:<:) xs ys where
neq (a:<:b) = a /= b
facts :: Eq a => [[a]] -> [CMP a]
facts xss = nub . concat $ zipWith fact xss (tail xss)
例子:
ghci> fact "wellbeing" "wellington"
['b' :<: 'i']
*Main ghci> facts example
['d' :<: 'c','a' :<: 'b','a' :<: 'd','b' :<: 'c']
我們將使用一種數據類型來表示部分排序-字符列表和一組比較,並且我們將使用facts
功能根據樣本排序的單詞生成比較,並使用nub.concat
技巧來獲取字母他們自己:
data Partial a = Partial {chars :: [a], order :: [CMP a]} deriving Show
partial :: Eq a => [[a]] -> Partial a
partial xss = Partial {chars = nub $ concat xss, order = facts xss}
例:
ghci> partial example
Partial{chars = "abdc",order = ['d' :<: 'c','a' :<: 'b','a' :<: 'd','b' :<: 'c']}
為了從部分順序中獲得可能的字母列表,我們首先需要找到哪些元素可以放在最前面。 只要您沒有什么都可以,可以nonBigs
,所以讓我們列出nonBigs
。 如果我們將潛在的第一個字母放在字母表的前面,則可以remove
其從剩余的部分順序中remove
:
nonBigs :: Eq a => [CMP a] -> [a] -> [a]
nonBigs lts as = filter (not.big) as where
big a = a `elem` (map (\ (_ :<: a) -> a) lts)
remove :: Eq a => a -> [CMP a] -> [CMP a]
remove a = filter no_a where
no_a (x :<: y) = not $ a `elem` [x,y]
示例:(唯一不比示例中'a'
東西大的是'a'
,並且有兩個事實不包含'a'
)
ghci> facts example
['d' :<: 'c','a' :<: 'b','a' :<: 'd','b' :<: 'c']
ghci> nonBigs (facts example) "abcd"
"a"
ghci> remove 'a' (facts example)
['d' :<: 'c','b' :<: 'c']
讓我們將nonBigs與除去字母的部分排序配對,以獲取所有可能的最小元素以及如何從那里繼續進行:
minima :: Eq a => Partial a -> [(a,Partial a)]
minima (Partial as lts) =
[(a,Partial (filter (/=a) as) (remove a lts) )|a <- nonBigs lts as]
示例:示例中必須首先具有'a'
,但是此后可以具有'b'
或'd'
:
ghci> minima $ partial example
[('a',Partial {chars = "bdc", order = ['d' :<: 'c','b' :<: 'c']})]
ghci> minima $ Partial {chars = "bdc", order = ['d' :<: 'c','b' :<: 'c']}
[('b',Partial {chars = "dc", order = ['d' :<: 'c']}),
('d',Partial {chars = "bc", order = ['b' :<: 'c']})]
復雜的位使用部分排序給出的“有向圖”來生長所有可能的樹狀路徑。 我們將使用樹木生長函數f :: input -> [(output,input)]
來告訴您所有可能的進行方法。 如果那沒有給您任何答案,我們需要[[]]
,這是一條空路徑,通過將每種可能性( treePaths f i'
)的可能的第一個元素放在前面( map (o:)
),可以遞歸地增長它:
treePaths :: (input -> [(output,input)]) -> input -> [[output]]
treePaths f i = case f i of
[] -> [[]]
pairs -> concat [map (o:) (treePaths f i') | (o,i') <- pairs]
alphabets list = treePaths minima (partial list)
示例: alphabets
長度的計算幾乎是即時的,但是alfabet
長度的計算在我(較舊的)筆記本電腦上需要2分鍾以上的時間; 僅生成所需的輸出比生成每個輸出並丟棄更快。
ghci> alphabets example
["abdc","adbc"]
ghci> length $ alphabets (sort $ words "hello there the their he and at ah eh")
15120
ghci> length $ alfabet (sort $ words "hello there the their he and at ah eh")
15120
如果您使用\\ls -> map head $ group $ map head ls
並將其用於您的["ab","abd","abc",ba","bd",cc"]
,這將為您提供"abc"
。 如果要對第二個符號重復類似的過程,其中第一個符號相同,則還將具有"b"
, "ad"
和"c"
。 這些部分字母足以找出所有可能的完整字母。
我建議使用所有部分字母來構建成對的列表(集合),這樣,如果列表中包含('a', 'b')
,則'a'
在'b'
之前。 然后,使用符號集作為比較器,將符號一一插入所有可能的位置。 確保考慮不確定的順序。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.