0

编辑:很难描述我想要做什么,但这里有一个尝试(来自评论):

我正在构建一个 wordfeud 求解器,所以我有一个单词和一些字母(都是字符列表)。我将此(如何在 Haskell 中查找字符串中字符的频率?)应用于两个列表以获取所有字母的频率。我现在正在做的是遍历“单词”字符列表,并检查所有字符是否在“字母”字符列表中充分出现。

我编写了一个 Haskell 函数,它通过将函数应用于两个列表的项目并比较结果来比较两个列表。

比较是这样进行的:

hasLetters' :: [Char] -> [Char] -> Bool
hasLetters' word letters = (getCharOccurrence (head word) (getCharOccurrences word)) <= (getCharOccurrence (head word) (getCharOccurrences letters))

这仅比较单词第一个字母的出现次数。但是应该比较所有单词(并且所有单词的结果都应该是 TRUE)。

我真的不知道如何做到这一点。我找到了让我定义谓词的“全部”方法,这非常好。它看起来像这样:

all (<= (getCharOccurrence (head word) (getCharOccurrences letters))) 

(我认为这是正确的)它确保进入列表的每个项目都小于或等于提供的函数的结果。

但是:'all' 方法需要另一个参数。这将是定义应该与谓词进行比较的“源”参数。当这只是一个列表时,这很容易,然后我会做这样的事情:

all (<= (getCharOccurrence (head word) (getCharOccurrences letters))) [0..10]

但问题是:我没有这样的结果列表,我需要将其与以下结果进行比较:

(getCharOccurrence (head word) (getCharOccurrences letters))

我想我可以使用“map”函数将此函数应用于“word”字符列表中的每个字符,但我不知道如何使用它。我是这样开始的:

map (getCharOccurrence (head word) (getCharOccurrences word)) word

但这是错误的。

所以我(认为我)需要的是:将上述函数应用于“单词”字符列表的所有字符,并将其与谓词进行比较。

但也许我只是想错了。我是一个绝对的 Haskell/函数式编程新手。请帮帮我:-)

4

3 回答 3

3

使用多集包:

import Data.MultiSet
compareAll as bs = fromList as `isSubsetOf` fromList bs

或者:

import Data.Function
import Data.MultiSet
compareAll = isSubsetOf `on` fromList
于 2012-07-01T03:01:36.137 回答
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. 这将为我们提供一个布尔列表。然后我们使用and来检查该列表的所有元素是否为True.

于 2012-07-01T00:15:10.850 回答
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)

等等等等。

于 2012-06-30T23:49:56.223 回答