【问题标题】:Check if differences between elements already exists in a list检查列表中是否已经存在元素之间的差异
【发布时间】:2020-06-13 13:17:43
【问题描述】:

我正在尝试为最简单可行的Golomb Ruler 构建一个启发式算法。从 0 到 n,找到 n 个数,使得它们之间的所有差异都不同。这种启发式方法包括每次将标尺增加 1。如果列表中已经存在差异,则跳转到下一个整数。所以标尺以 [0,1] 开头,差异列表 = [ 1 ]。然后我们尝试将 2 加到标尺 [0,1,2] 上,但这不可行,因为差异 (2-1 = 1) 已经存在于差异列表中。然后我们尝试将 3 添加到标尺 [0,1,3] 上,这是可行的,因此差异列表变为 [1,2,3] 等等。到目前为止,这是我所做的:

n = 5
positions = list(range(1,n+1))
Pos = []
Dist = []
difs = []
i = 0


while (i < len(positions)):
    if len(Pos)==0:
        Pos.append(0)
        Dist.append(0)
    elif len(Pos)==1:
            Pos.append(1)
            Dist.append(1)
    else:
        postest = Pos + [i] #check feasibility to enter the ruler
        difs = [a-b for a in postest for b in postest if a > b] 
        if any (d in difs for d in Dist)==True:
                pass
        else:
            for d in difs:
                Dist.append(d) 
            Pos.append(i) 
    i += 1

但是,我无法使差异检查起作用。有什么建议吗?

【问题讨论】:

    标签: python python-3.x heuristics


    【解决方案1】:

    为了提高效率,我倾向于使用集合来存储差异,因为它们有利于包含测试,并且您不关心排序(可能直到您实际打印出来,此时您可以使用 @ 987654321@).

    您可以使用一个临时集合来存储您正在测试的数字与您当前拥有的数字之间的差异,然后将其添加到现有集合中,或者如果您发现任何匹配项则将其丢弃。 (注意else 块在for 循环上,如果没有遇到break 将执行。)

    n = 5
    
    i = 0
    vals = []
    diffs = set()
    while len(vals) < n:
        diffs1 = set()
        for j in reversed(vals):
            diff = i - j
            if diff in diffs:
                break
            diffs1.add(diff)
        else:
            vals.append(i)
            diffs.update(diffs1)
        i += 1
    
    print(vals, sorted(diffs))
    

    显式循环值(而不是使用any)是为了避免不必要地计算候选数与所有现有值之间的差异,当大多数候选数不成功并且找到第一个匹配项后,循环可以提前中止。

    vals 也可以作为一个集合并使用add 而不是append(尽管类似地,您可能希望在打印时使用sorted)。在这种情况下,使用了一个列表,尽管原则上迭代它的顺序并不重要,但此代码会以相反的顺序迭代以首先测试较小的差异,因为可能会更快地拒绝不可用的候选者方式。使用 n=200 进行测试,代码在使用 reversed 时运行了大约 0.2 秒,在没有 reversed 时运行了大约 2.1 秒;随着n 的增加,这种效果会越来越明显。在 n=400 的情况下,使用和不使用 reversed 需要 1.7 秒与 27 秒。

    【讨论】:

    • 太好了。它工作正常且快速。为什么在 diffs |= diffs1 中不能使用 diffs.add(diffs1) ?
    • @fsimoyama 因为您想添加集合diffs1 的每个成员,所以您不想将集合添加为diffs 的元素(无论如何都不允许这样做,因为集合元素必须是不可变对象)。如果更清楚,diffs |= diffs1 可以替换为 diffs = diffs.union(diffs1)
    • @fsimoyama 实际上我在这里所做的是生成一个新集合,即联合并将其分配回名称diffs 并丢弃旧集合。它可能会更快(对于足够小的集合diffs1 和足够大的集合diffs)循环diffs1 的元素对每个元素执行diffs.add()。如果你愿意,我会让你比较时间。
    • @fsimoyama 实际上从头开始,似乎集合有一个我忘记的update 方法。我把它改成diffs.update(diffs1)
    • @fsimoyama 现在已更改(并测试了功能,但没有计时)。将update 想象成列表中的extend 方法,尽管当然是无序的。但它应该是我在记得之前提到的显式循环的一个更快的等价物 - 即它将元素添加到现有集合而不是创建一个新集合。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-21
    • 2013-05-06
    • 2011-01-24
    • 1970-01-01
    • 2021-12-17
    • 1970-01-01
    • 2011-04-23
    相关资源
    最近更新 更多