【问题标题】:Test if all N variables are different测试所有 N 个变量是否不同
【发布时间】:2015-10-08 21:38:10
【问题描述】:

我想创建一个所有选定变量都不相等的条件。 到目前为止,我的解决方案是比较每一对不能很好扩展的:

if A!=B and A!=C and B!=C:

我想对多个变量进行相同的检查,比如五个或更多,但与那么多变量相比,它会变得相当混乱。我该怎么做才能让它变得更简单?

【问题讨论】:

  • 您实际上在做什么需要您检查那么多条件?这有点代码味道。
  • 我同意@Makoto。什么要求你这样做?这听起来像是一个 xy 问题。
  • 这是一个检查 5 位候选人投票的程序,基本上它计算一个从 1 到 5 的优先票列表,选择“1”票数最高的人作为获胜者,但如果一个或多个具有相同数量的“1”票,然后根据“2”偏好票选择获胜者,如果它们相同,则选择“3”票,依此类推。这有点冗长,但那是任务集,除了这部分代码之外,我已经把它全部排序了。
  • 你能添加一个例子吗,因为可能有更简单的方法来做你想做的事
  • 这个候选人信息是如何存储的?它是一个显式的类吗?也就是说,票数是一个明确代表的类别吗?发布该代码可能会更好,因为您要求的内容与实际得到的内容有所不同...

标签: python logical-operators boolean-logic idioms


【解决方案1】:

创建一个集合并检查集合中的元素数量是否与您传递给它的列表中的变量数量相同:

>>> variables = [a, b, c, d, e]
>>> if len(set(variables)) == len(variables):
...     print("All variables are different")

一个集合没有重复的元素,所以如果你创建一个集合并且它的元素数量与原始列表中的元素数量相同,那么你就知道所有元素彼此不同。

【讨论】:

  • 假设对象是可散列的
  • 这也首先创建了整个集合,因此不会提前失败。当前两项不同时,for 循环可能已经中止。因此,平均运行时间取决于数据中预期差异的频率。
  • 虽然这可能是一个很好的答案,但我觉得这并没有真正解决实际问题。提问者应该回来(希望)澄清,但这种回答只会进一步混淆,而不是帮助解决任何问题。
【解决方案2】:

如果你可以散列你的变量(而且,呃,你的变量有一个有意义的__hash__),使用一个集合。

def check_all_unique(li):
    unique = set()
    for i in li:
        if i in unique: return False #hey I've seen you before...
        unique.add(i)
    return True #nope, saw no one twice.

O(n) 最坏情况。 (是的,我知道您也可以len(li) == len(set(li)),但如果找到匹配项,此变体会提前返回)

如果您不能散列您的值(无论出于何种原因)但可以有意义地比较它们:

def check_all_unique(li):
    li.sort()
    for i in range(1,len(li)):
       if li[i-1] == li[i]: return False
    return True 

O(nlogn),因为排序。基本上,对所有内容进行排序,然后成对比较。如果两件事相等,则它们应该彼此相邻排序。 (如果由于某种原因,您的__cmp__ 没有对彼此相邻的相同事物进行排序,1. wut 和 2. 请继续下一个方法。)

如果ne 是您拥有的唯一运算符....

import operator
import itertools
li = #a list containing all the variables I must check
if all(operator.ne(*i) for i in itertools.combinations(li,2)):
   #do something

我基本上是使用itertools.combinations 来配对所有变量,然后使用operator.ne 来检查是否不相等。这具有 O(n^2) 的最坏情况时间复杂度,尽管它仍然应该短路(因为生成器和 all 是惰性的)。如果你完全确定neeq 是相反的,你可以使用operator.eqany 来代替。

附录:Vincent 写了一个更多更易读的itertools 变体版本,看起来像

import itertools
lst = #a list containing all the variables I must check
if all(a!=b for a,b in itertools.combinations(lst,2)):
   #do something

附录 2:呃,对于足够大的数据集,排序变体可能应该使用heapq。仍然是 O(nlogn) 最坏的情况,但 O(n) 最好的情况。应该是这样的

import heapq
def check_all_unique(li):
    heapq.heapify(li) #O(n), compared to sorting's O(nlogn)
    prev = heapq.heappop(li)
    for _ in range(len(li)): #O(n)
       current = heapq.heappop(li) #O(logn)
       if current == prev: return False
       prev = current
    return True 

【讨论】:

  • 我认为它没有那么难看,尤其是如果你摆脱了operator.ne。类似all(a != b for a, b in combinations(lst, 2)).
【解决方案3】:

将值放入容器类型。然后只需循环通过容器,比较每个值。大约需要 O(n^2)。

伪代码:

a[0] = A; a[1] = B ... a[n];

for i = 0 to n do
  for j = i + 1 to n do
      if a[i] == a[j]
         condition failed

【讨论】:

  • 更好的是,为什么不首先从数组开始。这对于密切相关的变量是理想的,例如当您需要将变量列表相互比较时。
  • 但是创建set(variables) 只是 O(n),而且是一个非常快的 O(n)。
  • 是的,我没有考虑到这一点。是的,可能可以优化。
  • 嵌套的 for 循环(尤其是在同一范围内)是一种代码味道,表明您正在低效地做某事......
  • 好吧,将来肯定会这样做。谢谢
【解决方案4】:

您可以枚举一个列表并检查所有值是否都是该值在列表中的第一次出现:

a = [5, 15, 20, 65, 48]
if all(a.index(v) == i for i, v in enumerate(a)):
    print "all elements are unique"

一旦由于 Python 的 all() 函数的行为而检测到第一个重复项,这将允许短路。

或者等效地,枚举一个列表并检查是否有任何值不是该值在列表中的第一次出现:

a = [5, 15, 20, 65, 48]
if not any(a.index(v) != i for i, v in enumerate(a)):
    print "all elements are unique"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-10
    • 1970-01-01
    • 2011-08-05
    • 2021-03-22
    • 1970-01-01
    • 1970-01-01
    • 2015-10-10
    • 2012-06-09
    相关资源
    最近更新 更多