我需要在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
答案 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,您可以使用 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