如何在Haskell中合并所有相交(Set a)?

时间:2015-08-20 15:49:28

标签: haskell

我有一组由Data.SetSet (Set a)类型代表的集合。

我想结合其交集不为空的所有成员集。

等效地,如果 x y <,我希望图表的组件有一个连接 x y 的边缘/ em>在同一个Set中。

示例:

-- import qualified Data.Set as S
ghci> f $ S.fromList [S.fromList [1,2], S.fromList [2,3], S.fromList [5]]
> S.fromList [S.fromList [1,2,3], S.fromList [5]]

ghci> f $ S.fromList [ S.fromList [1,2], S.fromList [2,3], S.fromList [3,4] ]
> S.fromlist [ S.fromList [1,2,3,4] ]

什么是优雅的性能解决方案?

2 个答案:

答案 0 :(得分:5)

对于要合并的大量集合,您希望使用union find算法。

你可以在这里找到实现联合查找算法的Haskell代码:

https://github.com/erantapaa/union-find-example

此外,对于Int集合,您将要使用Data.IntSet - 效率更高。

之前我编写了以下内容,它不会传递合并集合:

这是一个折叠:

import qualified Data.Set as S
import Data.List (foldl')

mergeSets as = foldl' merge [] as

-- merge one set into a list of sets
merge [] a = [a]
merge (b:bs) a = if S.null (S.intersection a b)
                    then b : merge bs a
                    else (S.union a b) : bs

test = mergeSets [ S.fromList [1,2], S.fromList [2,3], S.fromList [5] ]

答案 1 :(得分:2)

此定义在复杂的<div id="div1"></div> <div id="div2"> <div id="div3"><img src="myurl" id="image" onclick="change(this);"/></div> </div>构造

上按预期工作

Solution:

Set (Set a)

简单的折叠不适用于复杂的import qualified Data.Set as S innerUnions :: Ord a => S.Set (S.Set a) -> S.Set (S.Set a) innerUnions = innerUnion' S.empty where innerUnion' :: Ord a => S.Set (S.Set a) -> S.Set (S.Set a) -> S.Set (S.Set a) innerUnion' seta setb | S.null setb = seta | otherwise = innerUnion' (S.insert unioned seta) stripped where (unioned,stripped) = S.foldl f (minElem, setb') setb' minElem = S.findMin setb setb' = S.deleteMin setb f :: Ord a => (S.Set a, S.Set (S.Set a)) -> S.Set a -> (S.Set a, S.Set (S.Set a)) f (x,xs) y | (not . S.null) (x `S.intersection` y) = (x `S.union` y, S.delete y xs) | otherwise = (x,xs) 构造。简单的折叠会产生不正确的结果

示例:

Set (Set a)

正确转型:

ghci> simpleFold $ S.fromList 
         [ S.fromList [1,2], S.fromList [2,3], S.fromList [3,4]
         , S.fromList [5], S.fromList [5,6], S.fromList [6]
         , S.fromList [8,9], S.fromList [0,9], S.fromList [0,1]]
> fromList [fromList [0,1,2,3,4],fromList [5,6],fromList [0,8,9]]

这是因为我们必须在构建结果集时使用输入集。折叠期间折叠无法访问整个输入集,只能在给定时间访问输入集的单个元素。这意味着转换函数无法正确地使用输入集中的元素,因为它无法访问输入集的所有元素。我们需要手动编写一个更复杂的折叠,同时消耗输入集并构建结果集。

上面的ghci> innerUnions $ S.fromList [ S.fromList [1,2], S.fromList [2,3], S.fromList [3,4] , S.fromList [5], S.fromList [5,6], S.fromList [6] , S.fromList [8,9], S.fromList [0,9], S.fromList [0,1]] > fromList [fromList [0,1,2,3,4,8,9],fromList [5,6]] 函数执行此同时消费&amp;应用于折叠时的结构。