我刚开始学习Haskell。我正在尝试获取两个单词之间所有常用字母的列表,例如"hello"
和"llama"
[ 'l', 'l' ]
,"happy"
和{{1} },"pay"
。
我尝试使用相交,但我遇到重复问题,[ 'a', 'p', 'y' ]
和"happy"
导致"pay"
。我不能删除重复项,因为它们可以存在,如第一个示例所示。
如果有任何建议,我将不胜感激。谢谢!
答案 0 :(得分:3)
您可以使用multiset包:
Data.MultiSet> fromList "hello" `intersection` fromList "llama"
fromOccurList [('l',2)]
Data.MultiSet> fromList "happy" `intersection` fromList "pay"
fromOccurList [('a',1),('p',1),('y',1)]
data-ordlist包还提供此功能:
Data.List Data.List.Ordered> sort "hello" `isect` sort "llama"
"ll"
Data.List Data.List.Ordered> sort "happy" `isect` sort "pay"
"apy"
答案 1 :(得分:0)
我认为这是使用Data.Map的理想情况。我将按如下方式实现:
import qualified Data.Map.Lazy as M
sharedLetters :: String -> String -> String
sharedLetters s1 s2 = let cm = foldr (checkMap (\(x,y) -> (x,y+1))) charMap s2
where checkMap f c m = if M.member c m then M.adjust f c m
else M.insert c (f (0,0)) m
charMap = foldr (checkMap (\(x,y) -> (x+1,y))) M.empty s1
in M.foldlWithKey (\r k (v1,v2) -> r ++ replicate (minimum [v1,v2]) k) "" cm
main :: IO String
main = do
putStr "Enter first string :"
s1 <- getLine
putStr "Enter second string :"
s2 <- getLine
return $ sharedLetters s1 s2
Enter first string :happy
Enter second string :pay
"apy"
Enter first string :pay
Enter second string :happy
"apy"
Enter first string :hello
Enter second string :llama
"ll"
Enter first string :llama
Enter second string :hello
"ll"
答案 2 :(得分:0)
这是一项值得学习的好技巧。假设您有两个排序列表:
[1,1,5,10,15,15,18]
[2,5,8,10,15,20]
并且您希望将它们合并到一个排序列表中。在Haskell中,使用模式匹配和保护来编写此算法是一种非常优雅的方法:
merge (x:xs) (y:ys) | x < y = x : merge xs (y:ys)
| otherwise = y : merge (x:xs) ys
merge xs [] = xs
merge [] ys = ys
这样:
> merge [1,1,5,10,15,15,18] [2,5,8,10,15,20]
[1,1,2,5,5,8,10,10,15,15,15,18,20]
>
简而言之,当两个列表都非空时,它会比较两个列表的头部并输出最小的头部;然后它使用递归输出“其余的”。
它也可以用三种情况(更少,更大,更平等)写成所有明确的:
merge (x:xs) (y:ys) | x < y = x : merge xs (y:ys)
| x > y = y : merge (x:xs) ys
| otherwise = y : merge (x:xs) ys
merge xs [] = xs
merge [] ys = ys
这个通用模板可用于在排序列表上实现许多有趣的算法。这是删除常用元素的元素,例如:
uncommon (x:xs) (y:ys) | x < y = x : uncommon xs (y:ys)
| x > y = y : uncommon (x:xs) ys
| otherwise = uncommon xs ys
uncommon xs [] = xs
uncommon [] ys = ys
这样:
> uncommon [1,1,5,10,15,15,18] [2,5,8,10,15,20]
[1,1,2,8,15,18,20]
>
您可能希望尝试修改uncommon
函数以创建diff
函数,该函数输出从第一个列表中删除第二个列表元素的结果。它需要修改前三个受保护案例中的一个,你还需要调整两个“空列表”模式匹配中的一个:
> diff [1,1,5,10,15,15,18] [2,5,8,10,15,20]
[1,1,15,18]
>
一旦你弄明白这一点,你会发现创建一个common
函数很容易,它输出两个排序列表的共享元素给出:
> common [1,1,5,10,15,15,18] [2,5,8,10,15,20]
[5,10,15]
>
由于字符串只是字符列表,因此使用sort
中的Data.List
对列表进行预排序也可以解决您的问题:
> import Data.List
> common (sort "hello") (sort "llama")
"ll"
> common (sort "happy") (sort "pay")
"apy"
>
答案 3 :(得分:0)
利用这些单词之间共享的每个字母(允许重复)的事实如何显示为由这些单词的结合形成的集合中的一对字母?您可以通过对联合集进行排序并选择重复项来有效地找到这些对 -
let find_dups ([]) = []; find_dups (x:y:xs) | x == y = x:find_dups(xs); find_dups (x:xs) = find_dups(xs)
let common_letters word1 word2 = find_dups (sort (word1 ++ word2))
> common_letters "hello" "fellows"
"ello"