复杂的数据关系合并

时间:2012-01-11 15:05:07

标签: optimization haskell graph set relation

假设我有一组看起来像这样的关系:

relations :: [(A, B)]
instance Monoid A
instance Monoid B

我想将这组关系转换为A s和B s的一组新关系。

现在,这里有一些棘手的事情:

    平等的
  1. A应该有B s mappend ed。
  2. 平等的
  3. B应该有A s mappend ed。
  4. 重复直到所有AB s不同(或者不要,取决于是否可以某种方式非迭代地完成)。
  5. 编辑:排序限制使问题变得微不足道,所以我删除了它。

    可以假设OrdHashable或其他您需要的其他内容。出于所有意图和目的,可以说A行为完全完全,如HashSetB行为完全,如{{1} (或其他一些具有合理大小检查的类型)。

    这意味着可以假设Vectorlet s = size (mappend a b); s >= size a; s >= size b等。

    此转换将如何发生的示例(假设a, b :: B; mappend a b /= mappend b a <=> a, b not mempty; a > b => (mappend a c) > b<a, b>

    Set.fromList [a, b]

    如何以尽可能有效的方式(时间,空间)完成?

1 个答案:

答案 0 :(得分:2)

我认为一般情况不能比使用O(n ^ 2)合并的简单方法更好,因此总算法可以是O(n ^ 3)。在不限制列表中元素的顺序和mappend的结果的情况下,您必须匹配每对元素以查看它们是否应该合并,并重复直到完成。

merge :: Eq e => (a -> a -> a) -> (a -> e) -> [a] -> (Bool,[a])
merge combine eqval [] = (False, [])
merge combine eqval (x:xs) = (not (null a) || t, y : zs)
  where
    e = eqval x
    (a,b) = partition ((e ==) . eqval) xs
    y = mconcat (x:a)
    (t,zs) = merge combine eqval b

mergeRelations :: [(A,B)] -> [(A,B)]
mergeRelations = go False
  where
    mergeFsts = merge (\(a1,b1) (a2,b2) -> (a1, b1 `mappend` b2)) fst
    mergeSnds = merge (\(a1,b1) (a2,b2) -> (a1 `mappend` a2, b1)) snd
    go started xs
      | started && not f = xs
      | s = go True n
      | otherwise = m
        where
          (f,m) = mergeFsts xs
          (s,n) = mergeSnds m