在Haskell中编写以下代码是否有更好,更简洁的方法?我尝试过使用if..else
,但这比以下内容的可读性低。我想避免遍历xs
列表(这是巨大的!)8次,只是将元素分成8组。来自groupBy
的{{1}}只需要一个测试条件函数:Data.List
。
(a -> a -> Bool) -> [a] -> [[a]]
答案 0 :(得分:5)
这只会遍历列表一次:
import Data.Functor
import Control.Monad
filterN :: [a -> Bool] -> [a] -> [[a]]
filterN ps =
map catMaybes . transpose .
map (\x -> map (\p -> x <$ guard (p x)) ps)
对于列表中的每个元素,map
生成一个Maybe
列表,每个Maybe
对应一个谓词;如果元素不满足谓词,则为Nothing
;如果元素满足谓词,则为Just x
。然后,transpose
混洗所有这些列表,以便列表按谓词而不是按元素组织,map catMaybes
丢弃不满足谓词的元素的条目。
一些解释:x <$ m
为fmap (const x) m
,而对于Maybe
,guard b
为if b then Just () else Nothing
,因此x <$ guard b
为if b then Just x else Nothing
map
也可以写为map (\x -> [x <$ guard (p x) | p <- ps])
。
答案 1 :(得分:4)
如果你只坚持一次遍历列表,你可以写
filterMulti :: [a -> Bool] -> [a] -> [[a]]
filterMulti fs xs = go (reverse xs) (repeat []) where
go [] acc = acc
go (y:ys) acc = go ys $ zipWith (\f a -> if f y then y:a else a) fs acc
答案 2 :(得分:3)
map (\ cond -> filter (check cond) xs) [condition1, condition2, ..., condition8]
答案 3 :(得分:2)
我认为您可以使用GHC.Exts中的groupWith
。
如果您编写a -> b
函数来分配xs
其“类”中的每个元素,我相信groupWith
会按照您希望的方式分割xs
,只穿过一次列表。
答案 4 :(得分:1)
groupBy
并没有真正做到你想要的;即使它确实接受了多个谓词函数,它也不会对列表进行任何过滤。它只是将满足某些条件的列表元素的连续运行组合在一起。即使您的过滤条件组合在一起,也涵盖了所提供列表中的所有元素,这仍然是一个不同的操作。例如,groupBy
不会修改列表元素的顺序,也不会在结果中多次包含给定元素,而您的操作可以同时执行这两项操作。
此功能可以满足您的需求:
import Control.Applicative
filterMulti :: [a -> Bool] -> [a] -> [[a]]
filterMulti ps as = filter <$> ps <*> pure as
举个例子:
> filterMulti [(<2), (>=5)] [2, 5, 1, -2, 5, 1, 7, 3, -20, 76, 8]
[[1, -2, 1, -20], [5, 5, 7, 76, 8]]
答案 5 :(得分:1)
作为nietaki答案的附录(这应该是一个评论,但它太长了,所以如果他的答案是正确的,接受他的!),函数a -> b
可以写成一系列嵌套{{1但是,这不是非常惯用的Haskell,也不是非常可扩展的。这可能稍好一点:
if ... then .. else
它按照它满足的第一个import Data.List (elemIndex)
import GHC.Exts (groupWith)
f xs = groupWith test xs
where test x = elemIndex . map ($ x) $ [condition1, ..., condition8]
对每个元素进行分类(并将那些不满足任何元素的元素放入它们自己的类别中)。
(condition_
的文档是here。)
答案 6 :(得分:1)
第一个函数将返回“uppdated”列表的列表,第二个函数将遍历整个列表,并为每个值uppdate列表
myfilter :: a -> [a -> Bool] -> [[a]] -> [[a]]
myfilter _ [] [] = []
myfilter x f:fs l:ls | f x = (x:l): Myfilter x fs ls
| otherwise = l:Myfilter x fs ls
filterall :: [a] -> [a -> Bool] -> [[a]] -> [[a]]
filterall [] _ l = l
filterall x:xs fl l:ls = filterall xs fl (myfilter x fl l)
应使用filterall xs [condition1,condition2...] [[],[]...]