【问题标题】:Merging unsorted collections合并未排序的集合
【发布时间】:2021-03-31 21:32:53
【问题描述】:

假设我有两个集合:

A = [约翰、玛丽、弗兰克、伊莎贝尔、特蕾莎]

B = [麦迪逊、约翰、弗兰克、伊莎贝尔、鲍勃]

算法应该产生以下结果:

合并 = [麦迪逊、约翰、玛丽、弗兰克、伊莎贝尔、特蕾莎、鲍勃]

(虽然特蕾莎和鲍勃互换也可以)

换句话说,算法应该使用两个输入集合的现有排序来创建一个合并集合。理论上存在无限数量的可能元素,并且没有可以从中获取元素顺序的“主”列表。

对于我的用例,输入集合将相当小(通常少于 50 个项目),并且集合之间的大多数项目将相同,但这不能保证。

这是一种已知类型的算法吗?我一直在寻找合并算法,但大多数都在谈论有序列表及其性能优化。

----- 编辑 ------

还有几个例子:

第一个附加示例: A = [约翰、玛丽、弗兰克、伊莎贝尔、特蕾莎、罗伯特、鲍勃、安娜、泰莎、菲利普] B = [约翰、玛丽、罗伯特、鲍勃、菲利普、尼古拉斯] 合并 = [约翰、玛丽、弗兰克、伊莎贝尔、特蕾莎、罗伯特、鲍勃、安娜、泰莎、菲利普、尼古拉斯]

(因此算法应该推断出 Nicholas 应该位于 Philip 之后,因为在集合 B 中也是如此)

第二个附加示例: A = [约翰、玛丽、弗兰克、伊莎贝尔、特蕾莎、罗伯特、鲍勃、安娜、泰莎、菲利普] B = [贝蒂、约翰、鲍勃、菲利普、尼古拉斯、鲍里斯] 合并 = [贝蒂、约翰、玛丽、弗兰克、伊莎贝尔、特蕾莎、罗伯特、鲍勃、安娜、泰莎、菲利普、尼古拉斯、鲍里斯]

(因此算法应该推断出 Betty 应该位于 John 之前,Nicholas & Boris 位于 Philip 之后)

【问题讨论】:

  • B.zip(A).flatten.uniq.compact 会为您解决问题吗?我从您的示例中推断出您想要每个元素的第一个元素,然后是第二个元素,等等,因此是 zip。否则,(B + A).uniq.
  • 简单地展平不是解决方案,尽管我完全明白你为什么建议这样做。示例集合可能有点过于简单,抱歉!
  • 关于混淆示例中的正确顺序:这不是问题,因为集合之间的大多数项目将是相同的(集合实际上是彼此的小突变)。如果对正确排序有歧义,那么任何输出都适合我的用例。

标签: algorithm array-merge


【解决方案1】:

这是拓扑排序的一种变体,如果x 在任一列表中出现在y 之前,则关系为x < y

只要有可能,此算法就会生成合并列表:

  • 如果两个列表的头相同,则将该头添加到结果中,然后将其从两个列表中删除。
  • 如果任一列表的头部不在另一个列表中,请将其添加到结果中,然后将其从所在列表中删除。
  • 否则,没有结果可以保留两个列表中元素的顺序。

您可以通过为列表中剩余元素的每个列表保留一个集合,或者为每个列表构建一个映射,将元素映射到它们在列表。

【讨论】:

  • 这是正确的答案,假设每个列表中的元素是不同的,这似乎是这种情况。如果输入列表可以包含重复项(即在其中一个列表中多次出现的元素),那么它就是shortest common supersequence problem,它(对于两个列表)可以通过动态编程在 O(n^2) 时间内解决,或由最长的公共子序列构成。
  • 看它的有趣方式,我真的没有想到它。很有趣!
【解决方案2】:

如果我正确理解您的问题,您希望合并两个数组,同时保护它们的顺序并删除连续重复。

为了做到这一点,我们可以简单地循环更大的数组,并且在每个循环中我们可以控制列表长度、连续重复等...

代码:

A = ["John", "Mary", "Frank", "Isabel", "Teresa"]
B = ["Madison", "John", "Frank", "Isabel", "Bob"]

# Determine the bigger array length.
loop_count = len(A)
if len(B) > len(A):
    loop_count = len(B)

# Loop the arrays and append to merged array if not out of index,
# or not consecutive duplicate.
merged = []   
for i in range(0, loop_count):
    if i < len(A):
        if len(merged) == 0 or merged[-1] != A[i]:
            merged.append(A[i])
    if i < len(B):
        if len(merged) == 0 or merged[-1] != B[i]:
            merged.append(B[i])

print(merged)

输出:['John', 'Madison', 'Mary', 'John', 'Frank', 'Isabel', 'Teresa', 'Bob']

它不是完美的解决方案,有更好的方法来优化它,但既然你说你的数组相当小,它应该足够好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-20
    • 2023-03-28
    • 2017-10-05
    • 2014-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-26
    相关资源
    最近更新 更多