编辑:很难描述我正在尝试做什么,但这是一次尝试(来自评论):
我正在构建一个wordfeud求解器,所以我有一个单词和一些字母(两个字符列表)。我将此(How to find the frequency of characters in a string in Haskell?)应用于两个列表以获取所有字母的频率。我现在正在做的是迭代'word'字符列表,并检查所有字符是否在'letters'字符列表中充分发生。
我编写了一个Haskell函数,通过将函数应用于两个列表的项目并比较结果来比较两个列表。
比较如下:
hasLetters' :: [Char] -> [Char] -> Bool
hasLetters' word letters = (getCharOccurrence (head word) (getCharOccurrences word)) <= (getCharOccurrence (head word) (getCharOccurrences letters))
这只比较单词第一个字母的出现次数。但是应该比较所有单词(并且所有单词的结果都应该为TRUE。)
我真的不知道如何做到这一点。我找到了'all'方法,可以让我定义一个谓词,这非常好。它看起来像这样:
all (<= (getCharOccurrence (head word) (getCharOccurrences letters)))
(我认为这是正确的) 它确保进入列表的每个项目都小于或等于提供的函数的结果。
但是:'all'方法需要另一个参数。这将是'source'参数,用于定义应与谓词进行比较的内容。当这只是一个列表时,这很容易,然后我会做这样的事情:
all (<= (getCharOccurrence (head word) (getCharOccurrences letters))) [0..10]
但问题是:我没有这样的结果列表,我需要将它与结果进行比较:
(getCharOccurrence (head word) (getCharOccurrences letters))
我想我可以使用'map'函数将此函数应用于'word'字符列表中的每个字符,但我不知道如何使用它。我开始是这样的:
map (getCharOccurrence (head word) (getCharOccurrences word)) word
但那是错的。
所以我(我认为)需要:将上述函数应用于'word'字符列表的所有字符,并将其与谓词进行比较。
但也许我只是想错了路。我是一个绝对的Haskell /函数式编程新手。请帮帮我: - )
答案 0 :(得分:3)
使用multiset包:
import Data.MultiSet
compareAll as bs = fromList as `isSubsetOf` fromList bs
或:
import Data.Function
import Data.MultiSet
compareAll = isSubsetOf `on` fromList
答案 1 :(得分:2)
因此,根据我的理解,您有一个字符串word
,其中包含您想要形成的字词以及代表您可以使用的图块的字符letters
列表。你想检查这个词是否可以由瓷砖组成。
这里我假设你提到的功能有类型
getCharOccurrence :: Char -> [(Char, Integer)] -> Integer
getCharOccurrences :: [Char] -> [(Char, Integer)]
首先,您需要修改hasLetters'
以获取Char参数,而不是使用head word
:
hasLetters' :: Char -> [Char] -> [Char] -> Bool
hasLetters' c word letters = (getCharOccurrence c (getCharOccurrences word)) <= (getCharOccurrence c (getCharOccurrences letters))
然后你可以将上面的内容与一个主函数(我们称之为sufficientTiles
)结合起来
sufficientTiles :: [Char] -> [Char] -> Bool
sufficientTiles word letters = and $ map (\c -> hasLetters' c word letters) word
我们在此处所做的是将hasLetter'
函数映射到word
的每个字符。这将给我们一个Bools列表。然后,我们使用and
检查该列表的所有元素是否为True
。
答案 2 :(得分:1)
所以我想我明白你想要比较两个列表。如果第二个列表至少具有与第一个列表一样多的每个元素,则测试通过。因此,你需要一个至少相等的约束,但顺序会有所帮助。
有许多解决方案,首先想到的是对每个列表进行排序,对唯一元素进行分组和计数,并确保所有结果均为<=
:
someCompare a b = let op :: String -> [(Char,Int)]
op = map (head &&& length) . group . sort
in [c <= k | (x,c) <- op a, k <- maybeToList (lookup x (op b))]
或者您可以使用计数器地图并将两个地图联合起来:
someCompare2 a b =
let op = foldl' (\m c -> Map.insertWith (+) c 1 m) Map.empty
in all (<= 0) . Map.elems $ Map.unionWith (+) (op a) (Map.map negate $ op b)
Etc等。