代码之家  ›  专栏  ›  技术社区  ›  bogatyrjov

在haskell中过滤列表

  •  2
  • bogatyrjov  · 技术社区  · 14 年前

    我正试图开始学习哈斯克尔,这时出现了一个问题。 我有一个功能

    countFilter :: (a -> Bool) -> [a] -> ([a], Int)
    countFilter a z = case z of []        -> ([], 0);
                                (x:xs)    -> (filter a z , length (filter a z))
    

    它返回一个列表,其中的所有项都应用于某个谓词,并且该列表的长度不相关。

    countFilter (<7) [1,2,4,7,11,8,2] 意志输出 ([1,2,4,2], 4) .

    如何创建这样的输出: ([7,11,8], 4) 使用相同的谓词(<7)?

    1 回复  |  直到 14 年前
        1
  •  5
  •   Tom Lokhorst    14 年前

    如果我正确理解你的问题,你需要返回 不要 匹配谓词 (< 7) 作为对的第一个元素。

    在这种情况下,您可以简单地使用 not 函数来翻转结果布尔值。
    即创建一个新的谓词 (\x -> not (oldPred x)) 或使用函数组合: (not . oldPred) :

    countFilter :: (a -> Bool) -> [a] -> ([a], Int)
    countFilter f xs = (filter (not . f) xs, length (filter f xs))
    

    注意这两者 filter length 可以处理空列表,因此不需要编写 case 你自己。


    或者,您可以使用 partition 函数来创建两个列表,这样就不会对列表进行两次筛选:

    import Data.List
    
    countFilter :: (a -> Bool) -> [a] -> ([a], Int)
    countFilter f xs = let (ys, zs) = partition (not . f) xs
                       in (ys, length zs)
    

    可能可以创建一个更高效的版本,而不使用 长度 ,但我把它作为练习放在一边:—)