查找两个列表的所有可能的交叉点

时间:2015-02-21 13:27:27

标签: list haskell intersection

说我有一个列表[2,4,1,5,4]和一个列表[2,4,5,1]然后我希望有一个交叉函数,它将给我所有可能的交叉点。因此,在这种情况下,函数将输出[[2,4,1,5],[2,1,5,4]]的列表。

内置的交叉将给我[4,2,1,5,4]。

我试图通过制作一个函数来开始

intersect' xs ys = xs \\ (xs \\ ys)

这只给了我一种可能性 - [2,1,5,4]。

我很感激任何帮助。

2 个答案:

答案 0 :(得分:0)

  

内置的交叉将给我[4,2,1,5,4]。

[4,2,1,5,4]开始,您可以使用此功能获取[[2,4,1,5], [2,1,5,4]]

uniqs :: Eq a => [a] -> [[a]]
uniqs  []    = [[]]
uniqs (x:xs)
    | x `elem` xs = map (x:) (uniqs (filter (/= x) xs)) ++ uniqs xs
    | otherwise   = map (x:) (uniqs xs)

然后您的intersections只是

intersections :: Eq a => [a] -> [a] -> [[a]]
intersections xs ys = uniqs (intersect xs ys)

答案 1 :(得分:0)

由于您使用的是第二个列表,例如多套装,因此请在类型中明确说明:

intersections :: Ord a => [a] -> MultiSet a -> [[a]]

列表和空多集的唯一交集是空列表

intersections _ m | M.null m = [[]]

没有空列表和非空多集的交叉点

intersections [] _ = []

给定一个非空列表和一个非空多重集,我们有所有使用第一个项目的交叉点,以及所有没有交叉的交叉点

intersections (a:as) m = with ++ without

如果列表中的第一项不在多重集中,那么没有使用它的交叉点

  where with = case M.lookup a m of
          Nothing -> []

如果它在多组中,那么使用该项目的交叉点只是在删除该项目的一个实例后,列表其余部分和多组交叉点的扩展,

          Just n -> map (a:) . intersections as $ update a (n-1) m

不使用该项目的交叉点可以通过递归轻松定义

        without = intersections as m

为了完整性,多集的定义:

import qualified Data.Map as M
import qualified Data.List as L

type MultiSet a = M.Map a Int

fromList :: Ord a => [a] -> MultiSet a
fromList = L.foldl' (\m a -> M.insertWith' (+) a 1 m) M.empty

toList :: MultiSet a -> [a]
toList = concatMap (uncurry $ flip replicate) . M.toList

update :: Ord a => a -> Int -> MultiSet a -> MultiSet a
update a 0 = M.delete a
update a n = M.insert a n