Haskell - 通过比较过滤列表

时间:2013-05-01 23:10:35

标签: list haskell compare

我需要在Haskell中使用掩码过滤列表。

它将函数应用于掩码列表的元素和数据列表中的相应元素,如果函数返回true,则数据列表中的相应元素将包含在返回的列表中。

例如,假设我想过滤掉大于掩码项的数据项:

filtermask (\m d -> d > m) [1, 5, 7] [5, 6, 7]→[5, 6]

任何可能解决这个问题的方法都很棒。到目前为止,我只做了

 filtermask f m d = f m d

返回TRUE

编辑:解决方案,感谢Tikhon的帮助:

filtermask f [] [] = []
filtermask f (fm:rm) (fd:rd)
  |f fm fd = fd:filtermask f rm rd
  |otherwise = filtermask f rm rd

3 个答案:

答案 0 :(得分:4)

基本上,您要做的是首先将掩码的每个元素与列表中的元素配对。我们可以使用zip执行此操作,这会为我们提供配对列表。

现在我们有一个对列表,我们想要使用比较函数(>或其他)来过滤它。 >函数的类型为Ord o => o -> o -> Bool;我们需要把它变成一个接受元组的函数。令人高兴的是,我们可以使用uncurry执行此操作; uncurry (>)为我们提供了Ord o => (o, o) -> Bool类型的函数。

由于我们已经有了一个对列表,我们可以使用这个函数来过滤它。现在我们只列出了我们想要保留的对;我们需要获得一个元素列表。我们可以通过在列表上映射像fst这样的投影函数来实现这一目的。

总而言之,我们得到:

filterMask :: (o -> o -> Bool) -> [o] -> [o] -> [o]
filterMask fn mask list = map fst (filter (uncurry fn) (zip list mask))

还有一个更微妙的技巧:如果掩码比我们的输入列表短,会发生什么?使用此功能,输出列表的其余部分将被抛出。如果这不是你想要的,你需要重复掩码。我们可以使用名为cycle的简洁函数来执行此操作,该函数会永久重复列表。那个版本将是:

filterMask fn mask list = map fst (filter (uncurry fn) (zip list (cycle mask)))

答案 1 :(得分:2)

由于你的问题是设计,两个相同大小的列表,一个功能工作及其元素,使用zip函数是一个很好的起点。这是像这样的工作,

# zip [1,2,3] [4,5,6] 
[(1,4),(2,5),(3,6)]

然后,对于每个元组,您必须检查谓词是否填充 这就像应用zip 一个函数,有一个功能。

# zipWith (\x y -> x + y) [1,2,3] [4,5,6] 
[5,7,9]

但是,应用的功能不仅仅是提供的功能 而且,如果谓词不满意,我们应该怎么做? 这两点由条件语句和Maybe类型管理 最后我们得到一个包含两种值Nothing和Just x的列表,我们想保留最后一个。 catMaybe完成这项工作。

# filtermask f m d = catMaybes $ zipWith (\x y -> if f x y then Just y else Nothing) m d

答案 2 :(得分:0)

问题应该分为两部分:

  1. 通过比较两个列表生成布尔掩码
  2. 根据布尔掩码过滤列表之一

对于 1,您可以使用 zipWith。对于 2,您可以使用 maskFilter:

maskFilter :: [Bool] -> [a] -> [a]
maskFilter mask xs = [x | (m,x) <- zip mask xs, m]

对于您的示例,您可以使用

let
    xs = [1,5,7]
    ys = [5,6,7]
    mask = zipWith (>) ys xs
in
    maskFilter mask ys