我需要一个函数,它接受一个列表并输出True,如果输入列表中的所有元素使用标准相等运算符计算彼此相等,否则输出False。

我觉得最好是遍历列表,比较相邻的元素,然后与所有结果布尔值。但我不知道最python的方法是什么。


当前回答

可以使用map和lambda吗

lst = [1,1,1,1,1,1,1,1,1]

print all(map(lambda x: x == lst[0], lst[1:]))

其他回答

可以使用map和lambda吗

lst = [1,1,1,1,1,1,1,1,1]

print all(map(lambda x: x == lst[0], lst[1:]))

出现使用itertools。Groupby(参见itertools食谱):

from itertools import groupby

def all_equal(iterable):
    g = groupby(iterable)
    return next(g, True) and not next(g, False)

或不带groupby:

def all_equal(iterator):
    iterator = iter(iterator)
    try:
        first = next(iterator)
    except StopIteration:
        return True
    return all(first == x for x in iterator)

您可以考虑使用许多其他的一行程序:

Converting the input to a set and checking that it only has one or zero (in case the input is empty) items def all_equal2(iterator): return len(set(iterator)) <= 1 Comparing against the input list without the first item def all_equal3(lst): return lst[:-1] == lst[1:] Counting how many times the first item appears in the list def all_equal_ivo(lst): return not lst or lst.count(lst[0]) == len(lst) Comparing against a list of the first element repeated def all_equal_6502(lst): return not lst or [lst[0]]*len(lst) == lst

但它们也有一些缺点,即:

all_equal and all_equal2 can use any iterators, but the others must take a sequence input, typically concrete containers like a list or tuple. all_equal and all_equal3 stop as soon as a difference is found (what is called "short circuit"), whereas all the alternatives require iterating over the entire list, even if you can tell that the answer is False just by looking at the first two elements. In all_equal2 the content must be hashable. A list of lists will raise a TypeError for example. all_equal2 (in the worst case) and all_equal_6502 create a copy of the list, meaning you need to use double the memory.

在Python 3.9中,使用perfplot,我们得到这些计时(越低的Runtime [s]越好):

这是一个有趣的阅读和思考。谢谢大家! 我不认为任何依赖于纯计数的方法对所有情况都是可靠的。sum也可以工作,但只适用于数字或长度(再次导致计数场景)。

但我喜欢简单,所以我想出了这个:

all(i==lst[c-1] for c, i in enumerate(lst))

或者,我确实认为@kennytm的这个聪明的方法也适用于所有情况(有趣的是,它可能是最快的)。所以我承认它可能比我的好:

[lst[0]]*len(lst) == lst

我认为一个聪明的小奖励也会起作用,因为set消除了重复(聪明是有趣的,但通常不是维护代码的最佳实践)。我认为@kennytm的方法仍然会更快,但只适用于大型列表:

len(set(lst)) == 1

但是Python的简单和聪明是我最喜欢的语言之一。再想一下,如果你必须修改列表,就像我实际上做的那样,因为我正在比较地址(并将删除开头/结尾空格并转换为小写以消除可能的不一致,我的将更适合这项工作)。所以“更好”是主观的,因为我在使用这个词时使用了引号!但是你也可以事先清理列表。

祝你好运!

使用itertools的更多版本。groupby,我发现它比原来的更清晰(下面有更多关于它的信息):

def all_equal(iterable):
    g = groupby(iterable)
    return not any(g) or not any(g)

def all_equal(iterable):
    g = groupby(iterable)
    next(g, None)
    return not next(g, False)

def all_equal(iterable):
    g = groupby(iterable)
    return not next(g, False) or not next(g, False)

以下是来自Itertools Recipes的原始版本:

def all_equal(iterable):
    g = groupby(iterable)
    return next(g, True) and not next(g, False)

注意,下一个(g, True)总是True(它不是一个非空元组就是True)。这意味着它的值不重要。它的执行纯粹是为了推进groupby迭代器。但是在返回表达式中包含它会导致读者认为它的值在那里被使用。因为它没有,我发现这是误导和不必要的复杂。我上面的第二个版本将next(g, True)视为它的实际用途,作为一个我们不关心其值的语句。

我的第三个版本走了一个不同的方向,并使用了第一个next的值(g, False)。如果根本没有第一个组(即,如果给定的可迭代对象为“空”),则该解决方案立即返回结果,甚至不检查是否有第二个组。

我的第一个解决方案基本上和第三个一样,只是使用任何一个。两种解决方案都读作“所有元素都是相等的……”没有第一组,也没有第二组。”

基准测试结果(虽然速度并不是我在这里的重点,但清晰才是重点,在实践中,如果有许多相等的值,大多数时间可能由组自己花费,减少了这些差异的影响):

Python 3.10.4 on my Windows laptop:

iterable = ()
 914 ns   914 ns   916 ns  use_first_any
 917 ns   925 ns   925 ns  use_first_next
1074 ns  1075 ns  1075 ns  next_as_statement
1081 ns  1083 ns  1084 ns  original

iterable = (1,)
1290 ns  1290 ns  1291 ns  next_as_statement
1303 ns  1307 ns  1307 ns  use_first_next
1306 ns  1307 ns  1309 ns  use_first_any
1318 ns  1319 ns  1320 ns  original

iterable = (1, 2)
1463 ns  1464 ns  1467 ns  use_first_any
1463 ns  1463 ns  1467 ns  next_as_statement
1477 ns  1479 ns  1481 ns  use_first_next
1487 ns  1489 ns  1492 ns  original
Python 3.10.4 on a Debian Google Compute Engine instance:

iterable = ()
 234 ns   234 ns   234 ns  use_first_any
 234 ns   235 ns   235 ns  use_first_next
 264 ns   264 ns   264 ns  next_as_statement
 265 ns   265 ns   265 ns  original

iterable = (1,)
 308 ns   308 ns   308 ns  next_as_statement
 315 ns   315 ns   315 ns  original
 316 ns   316 ns   317 ns  use_first_any
 317 ns   317 ns   317 ns  use_first_next

iterable = (1, 2)
 361 ns   361 ns   361 ns  next_as_statement
 367 ns   367 ns   367 ns  original
 384 ns   385 ns   385 ns  use_first_next
 386 ns   387 ns   387 ns  use_first_any

基准测试代码:

from timeit import timeit
from random import shuffle
from bisect import insort
from itertools import groupby

def original(iterable):
    g = groupby(iterable)
    return next(g, True) and not next(g, False)

def use_first_any(iterable):
    g = groupby(iterable)
    return not any(g) or not any(g)

def next_as_statement(iterable):
    g = groupby(iterable)
    next(g, None)
    return not next(g, False)

def use_first_next(iterable):
    g = groupby(iterable)
    return not next(g, False) or not next(g, False)

funcs = [original, use_first_any, next_as_statement, use_first_next]

for iterable in (), (1,), (1, 2):
    print(f'{iterable = }')
    times = {func: [] for func in funcs}
    for _ in range(1000):
        shuffle(funcs)
        for func in funcs:
            number = 1000
            t = timeit(lambda: func(iterable), number=number) / number
            insort(times[func], t)
    for func in sorted(funcs, key=times.get):
        print(*('%4d ns ' % round(t * 1e9) for t in times[func][:3]), func.__name__)
    print()
def allTheSame(i):
    j = itertools.groupby(i)
    for k in j: break
    for k in j: return False
    return True

适用于Python 2.4,它没有“all”。