数据关系的复杂合并

发布于 2024-12-26 20:29:58 字数 1377 浏览 3 评论 0原文

假设我有一组如下所示的关系:

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

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

现在,棘手的事情来了:

  1. 相等的 A 应该对其 B 进行 mappend 编辑。
  2. 相等的 B 应该对其 A 进行 mappend 编辑。
  3. 重复直到所有 AB 都不同(或者不不同,取决于是否可以以非迭代方式完成)。

编辑:排序约束使问题变得微不足道,因此我将其删除。

人们可以假设 OrdHashable 或您需要的任何其他内容是可用的。出于所有意图和目的,我们可以说 A 的行为完全类似于 HashSet,而 B 的行为完全 就像 Vector (或具有合理大小检查的其他类型)。

这意味着可以假设 let s = size (mappend ab); s>=尺寸a; s >= size b,并且 a, b :: B; mappend ab /= mappend ba <=>; a、b不为空; a> b => (映射ac)> b 等。

如何发生的示例(假设 Set.fromList [a, b]

[(<1>, [a]), (<4>, [d]), (<2>, [b]), (<5>, [e]), (<1>, [b]), (<2>, [a]), (<3>, [c])]
-- Merge `A`s for equal `B`s
[(<1,2>, [a]), (<4>, [d]), (<1,2> [b]), (<5>, [e]), (<3>, [c])]
-- Merge `B`s for equal `A`s
[(<1,2>, [a, b]), (<4>, [d]), (<5>, [e]), (<3>, [c])]
-- All values are distinct, so we're done.

此转换 这可以以尽可能有效的方式(时间、空间)完成吗?

Let's say that I have a set of relations that looks like this:

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

I want to transform this set of relations to a new set of relations of As and Bs.

Now, here comes the tricky stuff:

  1. As that are equal should have their Bs mappended.
  2. Bs that are equal should have their As mappended.
  3. Repeat until all As and Bs are distinct (Or don't, depending on if this can be done non-iteratively somehow).

EDIT: The ordering constraint made the problem trivial, so I removed it.

One can assume that Ord, Hashable, or whatever else you need is available. For all intents and purposes, one could say that A behaves exactly like HashSet and B behaves exactly like Vector (or some other type with reasonable size checking).

This means that one can assume that let s = size (mappend a b); s >= size a; s >= size b, and that a, b :: B; mappend a b /= mappend b a <=> a, b not mempty; a > b => (mappend a c) > b, etc.

An example of how this transformation would happen (Pretend that <a, b> is Set.fromList [a, b])

[(<1>, [a]), (<4>, [d]), (<2>, [b]), (<5>, [e]), (<1>, [b]), (<2>, [a]), (<3>, [c])]
-- Merge `A`s for equal `B`s
[(<1,2>, [a]), (<4>, [d]), (<1,2> [b]), (<5>, [e]), (<3>, [c])]
-- Merge `B`s for equal `A`s
[(<1,2>, [a, b]), (<4>, [d]), (<5>, [e]), (<3>, [c])]
-- All values are distinct, so we're done.

How can this be done in an as efficient manner as possible (time, space)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

心欲静而疯不止 2025-01-02 20:29:59

我认为一般情况不能比 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

I think the general case cannot be done any better than the straightforward way with an O(n^2) merge, so the total algorithm could be O(n^3). Without restrictions on the order of elements in the list and results of mappend, you have to match each pair of elements to see whether they should be merged, and repeat until done.

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文