如何在haskell中按字符串过滤字符串列表?

时间:2015-02-18 08:59:42

标签: string haskell filtering

我有一个包含字母的字符串,我希望确保它们在列表中的单词中。然而,运行它会导致它仍然留下包含不需要的字母的单词。

这是我的功能:

import Data.List    

filterWords :: String -> [String]
filterWords str =
  let strs      = words str
      letters   = concat . words . nub $ "poultry outwits ants"
      predicate = dropWhile (`elem` letters) ['a' .. 'z']
  in  dropWhile (any (`elem` predicate)) strs

我需要做些什么来改变这项工作?

为了说清楚,我想过滤掉任何包含不在“家禽狩猎蚂蚁”中的字母的单词,这意味着会删除像“年”这样的单词,因为尽管包含'y''a''r''s'都满足谓词,它还包含'e',但不包含。{/ p>

1 个答案:

答案 0 :(得分:4)

过滤事物列表(例如单词)的好方法是使用filter函数。您需要提供的是一个谓词,它告诉您是否应该包含字符串。您评论说要包含"poultry outwits ants"中由字母组成的字符串,这样就是

filterWords :: String -> [String]
filterWords str = filter acceptableWord (words str)
  where
    acceptableWord = all (`elem` "poultry outwits ants")

现在,在另一条评论中你写了

  

我得到的一些单词的副本数量与原单相同。

所以我怀疑你想要的是找出"poultry outwits ants"中的字母可以形成哪些字。

为此,您可以计算每个字符出现在给定单词(以及mgic字符串poultry outwits ants)中的频率,然后验证不仅单词中的每个字母都出现在魔术字符串中,还要验证这封信不会出现在魔术字符串中。

我首先定义一个计算字符频率表的函数,即计算每个字符出现在给定字符串中的频率:

freq :: String -> [(Char, Int)]
freq = map (\s -> (head s, length s)) . group . sort

此外,我定义了一个函数,它告诉一个频率表x是否是"子集"另一个表y,即它验证x中的每个字符是否也出现在y中,但它不会更频繁地出现:

subset :: [(Char, Int)] -> [(Char, Int)] -> Bool
subset x y = all f x
  where
    f (ch, occ) = case lookup ch y of
                      Just occ' -> occ <= occ'
                      Nothing   -> False

然后你可以使用它来定义acceptableWord,使它只接受频率表是魔术字符串频率表子集的单词,所以我们得到:

filterWords :: String -> [String]
filterWords str = filter acceptableWord (words str)
  where
    acceptableWord w = subset (freq w) (freq "poultry outwits ants")