Haskell比较所有列表项

时间:2012-06-30 23:03:14

标签: haskell functional-programming

编辑:很难描述我正在尝试做什么,但这是一次尝试(来自评论):

我正在构建一个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 /函数式编程新手。请帮帮我: - )

3 个答案:

答案 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等。