如何在Haskell中按另一个列表过滤列表?

时间:2015-10-08 13:35:57

标签: haskell

假设我有两个相同长度的列表A和B.我想在A中保留大于B中相应元素的元素。设A=[1,5,8], B=[2,4,9],结果应为[5],因为1<2, 5>4, 8<9.

我想出了一个解决方案。让C=zip A B,然后过滤C,最后通过取C中每个元素的fst得到结果。它不是那么优雅。有更简单的方法吗?

代码:

map fst (filter (\ x-> (fst x) > (snd x)) (zip a b))

6 个答案:

答案 0 :(得分:4)

您描述的解决方案对我来说很好。

另一种不一定更好的选择:

import Data.Maybe
import Control.Monad

catMaybes $ zipWith (\a b -> guard (a>b) >> return a) list1 list2

根据monad comprehensions的贬值,这也应该起作用

{-# LANGUAGE MonadComprehensions #-}

[ a | ( a <- list1 | b <- list2 ), a > b ]

......但实际上却没有。很遗憾,因为我发现它非常优雅。 我想知道我是错了还是GHC错误。

答案 1 :(得分:1)

我不确定您的代码看起来如何,但以下功能对我来说非常优雅:

File "main.py", line 3
    print num1, "is greater than", num2
        ^
IndentationError: expected an indented block

这种模式在Lisp社区中作为 decorate-process-undecorate 模式而众所周知。

答案 2 :(得分:1)

一种递归方法,不像其他方法那样优雅,这依赖于没有明确的压缩,我们在一次传递中得到结果,

greater :: Ord a => [a] -> [a] -> [a]
greater [] [] = []
greater (x:xs) (y:ys)  
    | x > y     = x : greater xs ys    
    | otherwise = greater xs ys

答案 3 :(得分:1)

我正在从事类似的工作,作为一个新手,这是我想出的最好的方法:

filterGreaterThan xs ys = do (x,y) <- zip xs ys
                             guard (x > y) 
                             return x

此解决方案比其他解决方案更容易推理。捐赠符号确实在这里闪耀。

答案 4 :(得分:0)

如果您想很好地概括这个想法,建议您参考mapMaybe

mapMaybe
  :: (a -> Maybe b)
  -> [a] -> [b]

将该想法应用于zipWith会产生结果

zipWithMaybe
  :: (a -> b -> Maybe c)
  -> [a] -> [b] -> [c]
zipWithMaybe f xs ys =
  [c | Just c <- zipWith f xs ys]

现在您可以编写函数了

keepGreater :: Ord a => [a] -> [a] -> [a]
keepGreater = zipWithMaybe $
  \x y -> x <$ guard (x > y)

真的值得麻烦吗?对于列表,可能不是。但是事实证明,在Data.Map的合并上下文中,类似的东西很有用。

答案 5 :(得分:0)

与@chi的列表一致解决方案非常相似:

concat $ zipWith (\a b -> last $ []:[[a] | a > b]) as bs