List Haskell-通过比较筛选列表
我需要用Haskell中的掩码筛选列表 它将函数应用于掩码列表的一个元素和数据列表中的对应元素,如果函数返回true,则数据列表中的对应元素将包含在返回的列表中 例如,假设我要筛选出大于掩码项的数据项:List Haskell-通过比较筛选列表,list,haskell,compare,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 这是真的 编辑:解决方案,感谢Tikhon的帮助: f
filtermask (\m d -> d > m) [1, 5, 7] [5, 6, 7]→[5, 6]
这个问题的任何可能的解决方案都将是梦幻般的。到目前为止,我只做了
filtermask f m d = f m d
这是真的
编辑:解决方案,感谢Tikhon的帮助:
filtermask f [] [] = []
filtermask f (fm:rm) (fd:rd)
|f fm fd = fd:filtermask f rm rd
|otherwise = filtermask f rm rd
基本上,您要做的是首先将掩码的每个元素与列表的一个元素配对。我们可以使用
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)))
由于您的问题是设计,两个相同大小的列表,以及一个正在工作的函数和它们的元素,使用zip函数是一个很好的起点。像这样的工作
# zip [1,2,3] [4,5,6]
[(1,4),(2,5),(3,6)]
然后,对于每个元组,必须检查谓词是否为fill。
这就像用一个函数应用一个zip,有一个函数
# zipWith (\x y -> x + y) [1,2,3] [4,5,6]
[5,7,9]
但是,应用的功能比提供的功能更多。
如果谓词不满足,我们该怎么办?
这两点由条件语句和类型管理。
最后我们得到一个列表,其中包含两种值,一种是零,另一种是x,我们希望保留最后一个值catMaybe
完成这项工作
# filtermask f m d = catMaybes $ zipWith (\x y -> if f x y then Just y else Nothing) m d
问题应分为两部分:
通过比较两个列表生成布尔掩码
基于布尔掩码筛选其中一个列表
对于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