【问题标题】:Python: determine if all items of a list are the same item [duplicate]Python:确定列表的所有项目是否都是同一个项目[重复]
【发布时间】:2010-09-24 14:14:55
【问题描述】:

在我的一些代码中,我将一系列对象放在一个列表中,并根据它们的属性构建一个附加列表,这是一个字符串。我需要确定第二个列表中的所有项目是否具有完全相同的值,而不事先知道它是哪个值,并返回一个布尔值,以便我可以根据结果在我的代码中做不同的事情。

我无法事先知道属性的名称,这就是为什么我要尽可能地制作一些通用的东西。

为了让这个例子更清楚,一个名为“all_same”的理想函数会这样工作:

>>> property_list = ["one", "one", "one"]
>>> all_same(property_list)
True
>>> property_list = ["one", "one", "two"]
>>> all_same(property_list)
False

我正在考虑制作一个独特元素的列表,然后检查其长度是否为 1,但我不确定这是否是最优雅的解决方案。

【问题讨论】:

  • 刚刚意识到我在这里问了同样的问题:stackoverflow.com/questions/3844801/…。如何将这两个问题联系起来?
  • 嘿,第一个问题我看到了前面的问题是重复的。时间有时会倒转。
  • 这个标题听起来像是提问者想要检查身份 (a is b),而不是平等 (a == b)跨度>

标签: python list


【解决方案1】:
def all_same(items):
    return all(x == items[0] for x in items)

示例:

>>> def all_same(items):
...     return all(x == items[0] for x in items)
...
>>> property_list = ["one", "one", "one"]
>>> all_same(property_list)
True
>>> property_list = ["one", "one", "two"]
>>> all_same(property_list)
False
>>> all_same([])
True

【讨论】:

  • 很好,我会用这个,谢谢!
  • len(set(items)) == 1 更快。
  • @muraveill 这在很大程度上取决于输入。
  • 这个答案有一些缺点:它只适用于可索引和相等(并且没有身份)。因此有一个稍微改进的版本: import operator def same(iterable, compare=operator.eq, value_on_empty=True): gen = iter(iterable) start = next(gen, value_on_empty) return all(compare(start, x) for x in gen) 这将适用于大小不一的可迭代对象,例如生成器,允许您指定“相同”的含义以及对空值执行的操作。
  • @e-satis 使用该版本改进了答案。
【解决方案2】:

你可以作弊并使用set:

def all_same( items ):
    return len( set( items ) ) == 1 #== len( items )

或者你可以使用:

def all_same( items ):
    return all( map(lambda x: x == items[0], items ) )

或者如果您处理的是可迭代对象而不是列表:

def all_same( iterable ):
    it_copy = tee( iterable, 1 )
    return len( set( it_copy) ) == 1

【讨论】:

  • 集合只有一项,列表有 N.
  • 您可以在第二个代码中使用生成器表达式。 all(x == items[0] for x in items).
  • len(set(items)) == 1 绝对是最惯用的。
  • 它也快得多:a = ["a"]*100; a[53]="b"%timeit len(set(a)) == 1 --> 每个循环 2.83us。 %timeit all(x==a[0] for x in a) --> 每个循环 7.78us。
  • @muraveill 你用的是什么机器,你能重现这些结果吗?我可以尝试在两台机器上得到相反的相对顺序:all() 方法比set() 方法快大约 3 倍。
【解决方案3】:

我最初将您解释为在测试身份(“相同的项目”),但您实际上是在测试平等(“相同的值”)。 (如果您正在测试身份,请使用 is 而不是 ==。)

def all_same(items):
  it = iter(items)
  for first in it:
    break
  else:
    return True  # empty case, note all([]) == True
  return all(x == first for x in it)

以上适用于任何可迭代的,而不仅仅是列表,否则您可以使用:

def all_same(L):
  return all(x == L[0] for x in L)

(但是,恕我直言,您不妨使用通用版本——它在列表上运行得非常好。)

【讨论】:

  • +1 我必须记住那个食谱。
  • @katrielalex:那么你必须尝试/除了 StopIteration;在这一点上,它是等效的行为和相同的长度。
  • 我更喜欢try: first = next(it) except StopIteration: return True——我认为流程更清晰——但确实有相同的区别。
  • @Roger:抱歉,注意到了,删除太晚了。确实! =)
  • 我喜欢这个解决方案。即使 OP 只要求列表,生成器现在在 Python 中如此普遍,最好不要假设输入是一个序列。请注意,您可以使用 Python >= 2.6 稍微简化一下: first = next(it, None)
【解决方案4】:

最好的方法是使用 Python 集合。你需要像这样定义all_same

def all_same(items):
    return len(set(items)) < 2

测试:

>>> def all_same(items):
...     return len(set(items)) < 2
... 
>>> 
>>> property_list = ["one", "one", "one"]
>>> all_same(property_list)
True
>>> property_list = ["one", "one", "two"]
>>> all_same(property_list)
False
>>> property_list = []
>>> all_same(property_list)
True

【讨论】:

  • 这对我不起作用,因为我的列表元素是字典,不能散列
【解决方案5】:

这适用于序列和可迭代对象:

def all_same(items):
  it = iter(items)
  first = next(it, None)
  return all(x == first for x in it)

【讨论】:

  • 啊,我在想你会检查first is None 而不是让这个失败。它确实给出了正确的结果,但我更愿意将此视为错误/“异常情况”,而不是依赖后面的代码默默地做正确的事情。
  • 我知道我在这个观点上非常不符合 Python 标准,但我不喜欢一个漂亮的单行变成四行,因为我必须捕获一个异常(我一般来说,你使用了 for/打破你的回答)。是的,我知道 EAFP,但是,如果我能避免它的话……谢谢你的 +1,不过 :-)
【解决方案6】:

如果您知道值在列表中,这可能会更快。

def all_same(values):
    return values.count(values[0]) == len(values)

【讨论】:

    【解决方案7】:

    经过深思熟虑后,我为同一问题创建了这个 sn-p 代码。我不确定它是否适用于所有场景。

    def all_same(list):
        list[0]*len(list) == list
    

    【讨论】:

    • 恐怕这根本行不通。例如。 test_list=[1, 1]all_same(test_list) 返回 False 因为 test_list[0] = 1len(test_list) = 2 所以结果只是 1 * 2 = 2。然后你测试2 == test_list,结果不正确。