haskell中的过滤功能

时间:2014-09-09 06:56:31

标签: haskell

我有两个列表

a = [1,2,3,4,5,6]
b = [3,4,5,6,7,8,9]

我想得到的结果是这两个列表的共同部分:[3,4,5,6] 我试图使用过滤功能,但它总是输出错误

filter (== a) b 
filter (== b) a

然后将它们组合在一起

7 个答案:

答案 0 :(得分:6)

您需要使用filter迭代一个列表,并使用elem函数检查该列表中的元素是否出现在另一个列表中:

inte :: Eq a => [a] -> [a] -> [a]
inte a b = filter (\x -> x `elem` a) b

另一种方法是查看是否存在任何内置库函数。首先,为所需函数编写类型签名:

[a] -> [a] -> [a]

然后运行hoogle query以查看是否有任何预建功能。 intersect中有一个Data.List功能,可以完全实现您的目标。

答案 1 :(得分:4)

如果只查看常用元素,请使用intersect

中的Data.List
a `intersect` b == [3,4,5,6]

相关问题:is there union and intersect Haskell Prelude implementation?

答案 2 :(得分:2)

您需要使用 intersect 函数从两个列表中获取常用元素。

了解如何在列表中使用intersect功能。

答案 3 :(得分:1)

虽然您可以直接在列表中使用intersect函数,但我建议您使用更高效的专用容器而不是列表。如果您真的想表达,那么为什么不使用Data.Set

  

前奏>导入合格的数据。设置为设置
  前奏集>设a = Set.fromList [1,2,3,4,5,6]; b = Set.fromList [3,4,5,6,7,8,9]
  加载包数组-0.5.0.0 ...链接...完成。
  加载包deepseq-1.3.0.2 ...链接...完成。
  装箱包装容器-0.5.5.1 ...连接......完成。
  前奏集> Set.intersection a b
  fromList [3,4,5,6]

这是 O n ⋅log n )而不是 O n 2 ),对于大型集合来说要快得多。此外,如果您使用专用的集合类型,它会更好地表达您的意图:它清楚地表明您计算重复项,并且没有任何重要的元素排序。

缺点是,元素需要Ord,因为实现使用规范排序。另一种选择是HashSet

答案 4 :(得分:1)

这是一个单行

[x | x <- a, y <- b, x == y ]

答案 5 :(得分:1)

intersect a b = [x| x <- a, x `elem` b]

a中使用列表x <- a参数作为生成器。布尔表达式x elem b过滤每个元素。如果True添加到x则丢弃。

答案 6 :(得分:0)

如果您的列表是由增加的正数构建的,那么您可以使用O(n)解决方案而不是二次intersect和朋友:

ordzip :: (Ord a, Num a) => [a] -> [a] -> [(a,a)]
ordzip a b = g a b where 
  g a@(x:r) b@(y:q)  | x < y     = (x,0) : g r b 
                     | y < x     = (0,y) : g a q 
                     | otherwise = (x,y) : g r q 
  g a       []                   = [(x,0) | x <- a]
  g []      b                    = [(0,y) | y <- b]

diff xs ys = [x | (x,y)<- ordzip xs ys, x/=0 && y==0 ]  -- set difference
meet xs ys = [y | (x,y)<- ordzip xs ys, x/=0 && y/=0 ]  --     intersection
joyn xs ys = [z | (x,y)<- ordzip xs ys, let z=max x y]  --     union

您想要的是meet

  

前奏&GT;符合[1,2,3,4,5,6] [3,4,5,6,7,8,9]
  [3,4,5,6]

上面只是一个玩具代码,给我们一个想法。通常情况下,您可以使用Maybe a来传达可能值的信息,而不是使用特殊分隔的元素,就像我上面使用0一样。类型Maybe a的值可以是NothingJust a

但实际上,我们永远不会有(Nothing, Nothing)组合,因为我们选择ordzip中的两个或两个中的一个,但从不 none ,对吧?所以我们真正需要的是Data.These.These

import Data.These

ordzip :: (Ord a) => [a] -> [b] -> [These a b]
ordzip a@(x:t) b@(y:r) = case compare x y of
                            LT -> This  x   : ordzip t b 
                            GT -> That    y : ordzip a r 
                            EQ -> These x y : ordzip t r 
ordzip a       []      = map This a
ordzip []      b       = map That b

diff = catThis .: ordzip 
meet = map snd .: catThese .: ordzip
joyn = map (these id id const) .: ordzip
-- infixr 8 .: ; (f .: g) x y = f (g x y)

通过将它们的定义与上面的ordzip合并来重写这三个集函数可以在某些情况下导致更高效的代码(例如,不需要使用ordzip a []或{{附加额外的尾部1}}只是因为它们在ordzip [] b中被丢弃了。而且,当其中一个参数列表是无限的而另一个是有限的时,它会使meet(或meet)正常生产。上面的三个定义更多是可执行规范

有时我们可能需要通过一些额外的谓词来决定相等性,而不仅仅是普通的diff,我们可能会以不同的方式构造结果的元素,因为我们可能需要它们(例如包括{{1} }和compare中的结果x

这些功能适用于有序列表。还有data-ordlist package,其中包含更多工具。