4

我需要在 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
4

3 回答 3

4

从根本上说,您要做的是首先将掩码的每个元素与列表的一个元素配对。我们可以用 来做到这一点zip,它给了我们一个配对列表。

现在我们有了一个配对列表,我们想使用比较函数(>或其他)过滤它。该>函数有一个类型Ord o => o -> o -> Bool;我们需要把它变成一个接受元组的函数。令人高兴的是,我们可以使用uncurry; uncurry (>)给了我们一个 type 的函数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)))
于 2013-05-01T23:24:45.477 回答
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
于 2013-05-01T23:32:16.217 回答
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
于 2021-01-30T05:04:52.247 回答