I need the following function:
我需要以下功能:
Input: a list
输入:一个列表
Output:
输出:
-
True
if all elements in the input list evaluate as equal to each other using the standard equality operator; - 如果输入列表中的所有元素都使用标准等式运算符相互求值,则为真;
-
False
otherwise. - 否则错误。
Performance: of course, I prefer not to incur any unnecessary overhead.
性能:当然,我不希望产生任何不必要的开销。
I feel it would be best to:
我觉得最好是:
- iterate through the list
- 遍历列表
- compare adjacent elements
- 比较相邻元素
- and
AND
all the resulting Boolean values - 以及所有产生的布尔值。
But I'm not sure what's the most Pythonic way to do that.
但我不确定什么是最符合python的方法。
EDIT:
编辑:
Thank you for all the great answers. I rated up several, and it was really hard to choose between @KennyTM and @Ivo van der Wijk solutions.
谢谢你的回答。我评分了好几次,很难在@KennyTM和@Ivo van der Wijk解决方案之间做出选择。
The lack of short-circuit feature only hurts on a long input (over ~50 elements) that have unequal elements early on. If this occurs often enough (how often depends on how long the lists might be), the short-circuit is required. The best short-circuit algorithm seems to be @KennyTM checkEqual1
. It pays, however, a significant cost for this:
缺少短路特性只会在很长一段时间内(超过50个元素)造成不相等的元素。如果这种情况经常发生(频率取决于列表的长度),就需要短路。最好的短路算法似乎是@KennyTM checkEqual1。然而,它为此付出了重大代价:
- up to 20x in performance nearly-identical lists
- 性能几乎相同的列表最高可达20倍
- up to 2.5x in performance on short lists
- 在短列表中的表现高达2.5倍
If the long inputs with early unequal elements don't happen (or happen sufficiently rarely), short-circuit isn't required. Then, by far the fastest is @Ivo van der Wijk solution.
如果具有早期不等元的长输入没有发生(或发生得足够少),则不需要短路。然后,到目前为止最快的是@Ivo van der Wijk解决方案。
20 个解决方案
#1
282
General method:
一般方法:
def checkEqual1(iterator):
iterator = iter(iterator)
try:
first = next(iterator)
except StopIteration:
return True
return all(first == rest for rest in iterator)
One-liner:
一行程序:
def checkEqual2(iterator):
return len(set(iterator)) <= 1
Also one-liner:
一行程序:
def checkEqual3(lst):
return lst[1:] == lst[:-1]
The difference between the 3 versions are that:
这三个版本的不同之处在于:
- In
checkEqual2
the content must be hashable. - 在checkEqual2中内容必须是可洗的。
-
checkEqual1
andcheckEqual2
can use any iterators, butcheckEqual3
must take a sequence input, typically concrete containers like a list or tuple. - checkEqual1和checkEqual2可以使用任何迭代器,但checkEqual3必须接受序列输入,通常是列表或tuple之类的具体容器。
-
checkEqual1
stops as soon as a difference is found. - 一旦发现差异,checkEqual1立即停止。
- Since
checkEqual1
contains more Python code, it is less efficient when many of the items are equal in the beginning. - 由于checkEqual1包含更多的Python代码,所以当许多项在开始时相等时,它的效率就会降低。
- Since
checkEqual2
andcheckEqual3
always perform O(N) copying operations, they will take longer if most of your input will return False. - 由于checkEqual2和checkEqual3始终执行O(N)复制操作,因此如果您的大多数输入将返回False,则需要更长时间。
-
checkEqual2
andcheckEqual3
can't be easily changed to adopt to comparea is b
instead ofa == b
. - checkEqual2和checkEqual3不能轻易更改为采用比较a是b而不是a = b。
timeit
result, for Python 2.7 and (only s1, s4, s7, s9 should return True)
对于Python 2.7和(只有s1、s4、s7、s9应该返回True)
s1 = [1] * 5000
s2 = [1] * 4999 + [2]
s3 = [2] + [1]*4999
s4 = [set([9])] * 5000
s5 = [set([9])] * 4999 + [set([10])]
s6 = [set([10])] + [set([9])] * 4999
s7 = [1,1]
s8 = [1,2]
s9 = []
we get
我们得到了
| checkEqual1 | checkEqual2 | checkEqual3 | checkEqualIvo | checkEqual6502 |
|-----|-------------|-------------|--------------|---------------|----------------|
| s1 | 1.19 msec | 348 usec | 183 usec | 51.6 usec | 121 usec |
| s2 | 1.17 msec | 376 usec | 185 usec | 50.9 usec | 118 usec |
| s3 | 4.17 usec | 348 usec | 120 usec | 264 usec | 61.3 usec |
| | | | | | |
| s4 | 1.73 msec | | 182 usec | 50.5 usec | 121 usec |
| s5 | 1.71 msec | | 181 usec | 50.6 usec | 125 usec |
| s6 | 4.29 usec | | 122 usec | 423 usec | 61.1 usec |
| | | | | | |
| s7 | 3.1 usec | 1.4 usec | 1.24 usec | 0.932 usec | 1.92 usec |
| s8 | 4.07 usec | 1.54 usec | 1.28 usec | 0.997 usec | 1.79 usec |
| s9 | 5.91 usec | 1.25 usec | 0.749 usec | 0.407 usec | 0.386 usec |
Note:
注意:
# http://*.com/q/3844948/
def checkEqualIvo(lst):
return not lst or lst.count(lst[0]) == len(lst)
# http://*.com/q/3844931/
def checkEqual6502(lst):
return not lst or [lst[0]]*len(lst) == lst
#2
216
A solution faster than using set() that works on sequences (not iterables) is to simply count the first element. This assumes the list is non-empty (but that's trivial to check, and decide yourself what the outcome should be on an empty list)
一个比使用set()更快的解决方案(不是迭代)是简单地计算第一个元素。这假设列表是非空的(但这是很容易检查的,并决定在空列表中结果应该是什么)
x.count(x[0]) == len(x)
some simple benchmarks:
一些简单的基准:
>>> timeit.timeit('len(set(s1))<=1', 's1=[1]*5000', number=10000)
1.4383411407470703
>>> timeit.timeit('len(set(s1))<=1', 's1=[1]*4999+[2]', number=10000)
1.4765670299530029
>>> timeit.timeit('s1.count(s1[0])==len(s1)', 's1=[1]*5000', number=10000)
0.26274609565734863
>>> timeit.timeit('s1.count(s1[0])==len(s1)', 's1=[1]*4999+[2]', number=10000)
0.25654196739196777
#3
94
The simplest and most elegant way is as follows:
最简单、最优雅的方式如下:
all(x==myList[0] for x in myList)
(Yes, this even works with the null list! This is because this is one of the few cases where python has lazy semantics.)
(是的,这甚至适用于空列表!)这是因为这是python具有惰性语义的少数情况之一。
Regarding performance, this will fail at the earliest possible time, so it is asymptotically optimal.
关于性能,这将会在尽可能早的时间内失败,因此它是渐进最优的。
#4
25
A set comparison work:
一组对比工作:
len(set(the_list)) == 1
Using set
removes all duplicate elements.
使用set删除所有重复的元素。
#5
22
You can convert the list to a set. A set cannot have duplicates. So if all the elements in the original list are identical, the set will have just one element.
你可以把列表转换成一个集合。一个集合不能有重复。如果原始列表中的所有元素都是相同的,那么这个集合就只有一个元素。
if len(sets.Set(input_list)) == 1
// input_list has all identical elements.
#6
10
For what it's worth, this came up on the python-ideas mailing list recently. It turns out that there is an itertools recipe for doing this already:1
不管怎么说,这是最近出现在python-ideas邮件列表中的。事实证明,已经有一个迭代工具的诀窍来实现这一点:1
def all_equal(iterable):
"Returns True if all the elements are equal to each other"
g = groupby(iterable)
return next(g, True) and not next(g, False)
Supposedly it performs very nicely and has a few nice properties.
据说它的性能非常好,并且有一些不错的性能。
- Short-circuits: It will stop consuming items from the iterable as soon as it finds the first non-equal item.
- 短路:当它发现第一个不相等的项时,它将停止从可迭代项中消费项。
- Doesn't require items to be hashable.
- 不需要可洗的东西。
- It is lazy and only requires O(1) additional memory to do the check.
- 它是惰性的,只需要O(1)额外的内存来完成检查。
1In other words, I can't take the credit for coming up with the solution -- nor can I take credit for even finding it.
换句话说,我不能因为提出了解决方案而受到赞扬,甚至我也不能因为找到了解决方案而受到赞扬。
#7
9
This is another option, faster than len(set(x))==1
for long lists (uses short circuit)
这是另一个选项,比len(set(x))= 1要快(使用短路)
def constantList(x):
return x and [x[0]]*len(x) == x
#8
4
This is a simple way of doing it:
这是一种简单的方法:
result = mylist and all(mylist[0] == elem for elem in mylist)
This is slightly more complicated, it incurs function call overhead, but the semantics are more clearly spelled out:
这有点复杂,它会导致函数调用开销,但是语义更清楚地说明了:
def all_identical(seq):
if not seq:
# empty list is False.
return False
first = seq[0]
return all(first == elem for elem in seq)
#9
3
Doubt this is the "most Pythonic", but something like:
怀疑这是“最符合python语言的”,但是类似:
>>> falseList = [1,2,3,4]
>>> trueList = [1, 1, 1]
>>>
>>> def testList(list):
... for item in list[1:]:
... if item != list[0]:
... return False
... return True
...
>>> testList(falseList)
False
>>> testList(trueList)
True
would do the trick.
就可以做到。
#10
3
Convert the list into the set and then find the number of elements in the set. If the result is 1, it has identical elements and if not, then the elements in the list are not identical.
将列表转换为集合,然后找到集合中元素的数量,如果结果是1,它有相同的元素,如果不是,那么列表中的元素就不相同。
list1 = [1,1,1]
len(set(list1))
>1
list1 = [1,2,3]
len(set(list1)
>3
#11
2
I'd do:
我想做的事:
not any((x[i] != x[i+1] for i in range(0, len(x)-1)))
as any
stops searching the iterable as soon as it finds a True
condition.
当any停止搜索iterable时,只要它找到一个真实的条件。
#12
2
If you're interested in something a little more readable (but of course not as efficient,) you could try:
如果你对可读性强一点的东西感兴趣(当然不是那么高效),你可以试试:
def compare_lists(list1, list2):
if len(list1) != len(list2): # Weed out unequal length lists.
return False
for item in list1:
if item not in list2:
return False
return True
a_list_1 = ['apple', 'orange', 'grape', 'pear']
a_list_2 = ['pear', 'orange', 'grape', 'apple']
b_list_1 = ['apple', 'orange', 'grape', 'pear']
b_list_2 = ['apple', 'orange', 'banana', 'pear']
c_list_1 = ['apple', 'orange', 'grape']
c_list_2 = ['grape', 'orange']
print compare_lists(a_list_1, a_list_2) # Returns True
print compare_lists(b_list_1, b_list_2) # Returns False
print compare_lists(c_list_1, c_list_2) # Returns False
#13
2
Regarding using reduce()
with lambda
. Here is a working code that I personally think is way nicer than some of the other answers.
关于对lambda使用reduce()。这里有一个我个人认为比其他答案更好的工作代码。
reduce(lambda x, y: (x[1]==y, y), [2, 2, 2], (True, 2))
Returns a truple where the first value is the boolean if all items are same or not.
返回一个truple,如果所有项都相同或不相同,则第一个值为布尔值。
#14
1
>>> a = [1, 2, 3, 4, 5, 6]
>>> z = [(a[x], a[x+1]) for x in range(0, len(a)-1)]
>>> z
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
# Replacing it with the test
>>> z = [(a[x] == a[x+1]) for x in range(0, len(a)-1)]
>>> z
[False, False, False, False, False]
>>> if False in z : Print "All elements are not equal"
#15
1
def allTheSame(i):
j = itertools.groupby(i)
for k in j: break
for k in j: return False
return True
Works in Python 2.4, which doesn't have "all".
适用于Python 2.4,它没有“全部”。
#16
1
Check if all elements equal to the first.
检查所有元素是否都等于第一个元素。
np.allclose(array, array[0])
np。allclose(数组,数组[0])
#17
1
Can use map and lambda
可以使用map和lambda吗
lst = [1,1,1,1,1,1,1,1,1]
print all(map(lambda x: x == lst[0], lst[1:]))
#18
1
Change the list to a set. Then if the size of the set is only 1, they must have been the same.
将列表更改为一个集合。如果集合的大小只有1,那么它们一定是相同的。
if len(set(my_list)) == 1:
#19
0
You can do:
你能做什么:
reduce(and_, (x==yourList[0] for x in yourList), True)
It is fairly annoying that python makes you import the operators like operator.and_
. As of python3, you will need to also import functools.reduce
.
python让您导入操作符(例如operator.and_)是相当烦人的。对于python3,您还需要导入函数。reduce。
(You should not use this method because it will not break if it finds non-equal values, but will continue examining the entire list. It is just included here as an answer for completeness.)
(您不应该使用这个方法,因为如果它发现不相等的值,它不会中断,而是将继续检查整个列表。它只是作为完整性的答案包含在这里)
#20
0
lambda lst: reduce(lambda a,b:(b,b==a[0] and a[1]), lst, (lst[0], True))[1]
The next one will short short circuit:
下一个将短路:
all(itertools.imap(lambda i:yourlist[i]==yourlist[i+1], xrange(len(yourlist)-1)))
#1
282
General method:
一般方法:
def checkEqual1(iterator):
iterator = iter(iterator)
try:
first = next(iterator)
except StopIteration:
return True
return all(first == rest for rest in iterator)
One-liner:
一行程序:
def checkEqual2(iterator):
return len(set(iterator)) <= 1
Also one-liner:
一行程序:
def checkEqual3(lst):
return lst[1:] == lst[:-1]
The difference between the 3 versions are that:
这三个版本的不同之处在于:
- In
checkEqual2
the content must be hashable. - 在checkEqual2中内容必须是可洗的。
-
checkEqual1
andcheckEqual2
can use any iterators, butcheckEqual3
must take a sequence input, typically concrete containers like a list or tuple. - checkEqual1和checkEqual2可以使用任何迭代器,但checkEqual3必须接受序列输入,通常是列表或tuple之类的具体容器。
-
checkEqual1
stops as soon as a difference is found. - 一旦发现差异,checkEqual1立即停止。
- Since
checkEqual1
contains more Python code, it is less efficient when many of the items are equal in the beginning. - 由于checkEqual1包含更多的Python代码,所以当许多项在开始时相等时,它的效率就会降低。
- Since
checkEqual2
andcheckEqual3
always perform O(N) copying operations, they will take longer if most of your input will return False. - 由于checkEqual2和checkEqual3始终执行O(N)复制操作,因此如果您的大多数输入将返回False,则需要更长时间。
-
checkEqual2
andcheckEqual3
can't be easily changed to adopt to comparea is b
instead ofa == b
. - checkEqual2和checkEqual3不能轻易更改为采用比较a是b而不是a = b。
timeit
result, for Python 2.7 and (only s1, s4, s7, s9 should return True)
对于Python 2.7和(只有s1、s4、s7、s9应该返回True)
s1 = [1] * 5000
s2 = [1] * 4999 + [2]
s3 = [2] + [1]*4999
s4 = [set([9])] * 5000
s5 = [set([9])] * 4999 + [set([10])]
s6 = [set([10])] + [set([9])] * 4999
s7 = [1,1]
s8 = [1,2]
s9 = []
we get
我们得到了
| checkEqual1 | checkEqual2 | checkEqual3 | checkEqualIvo | checkEqual6502 |
|-----|-------------|-------------|--------------|---------------|----------------|
| s1 | 1.19 msec | 348 usec | 183 usec | 51.6 usec | 121 usec |
| s2 | 1.17 msec | 376 usec | 185 usec | 50.9 usec | 118 usec |
| s3 | 4.17 usec | 348 usec | 120 usec | 264 usec | 61.3 usec |
| | | | | | |
| s4 | 1.73 msec | | 182 usec | 50.5 usec | 121 usec |
| s5 | 1.71 msec | | 181 usec | 50.6 usec | 125 usec |
| s6 | 4.29 usec | | 122 usec | 423 usec | 61.1 usec |
| | | | | | |
| s7 | 3.1 usec | 1.4 usec | 1.24 usec | 0.932 usec | 1.92 usec |
| s8 | 4.07 usec | 1.54 usec | 1.28 usec | 0.997 usec | 1.79 usec |
| s9 | 5.91 usec | 1.25 usec | 0.749 usec | 0.407 usec | 0.386 usec |
Note:
注意:
# http://*.com/q/3844948/
def checkEqualIvo(lst):
return not lst or lst.count(lst[0]) == len(lst)
# http://*.com/q/3844931/
def checkEqual6502(lst):
return not lst or [lst[0]]*len(lst) == lst
#2
216
A solution faster than using set() that works on sequences (not iterables) is to simply count the first element. This assumes the list is non-empty (but that's trivial to check, and decide yourself what the outcome should be on an empty list)
一个比使用set()更快的解决方案(不是迭代)是简单地计算第一个元素。这假设列表是非空的(但这是很容易检查的,并决定在空列表中结果应该是什么)
x.count(x[0]) == len(x)
some simple benchmarks:
一些简单的基准:
>>> timeit.timeit('len(set(s1))<=1', 's1=[1]*5000', number=10000)
1.4383411407470703
>>> timeit.timeit('len(set(s1))<=1', 's1=[1]*4999+[2]', number=10000)
1.4765670299530029
>>> timeit.timeit('s1.count(s1[0])==len(s1)', 's1=[1]*5000', number=10000)
0.26274609565734863
>>> timeit.timeit('s1.count(s1[0])==len(s1)', 's1=[1]*4999+[2]', number=10000)
0.25654196739196777
#3
94
The simplest and most elegant way is as follows:
最简单、最优雅的方式如下:
all(x==myList[0] for x in myList)
(Yes, this even works with the null list! This is because this is one of the few cases where python has lazy semantics.)
(是的,这甚至适用于空列表!)这是因为这是python具有惰性语义的少数情况之一。
Regarding performance, this will fail at the earliest possible time, so it is asymptotically optimal.
关于性能,这将会在尽可能早的时间内失败,因此它是渐进最优的。
#4
25
A set comparison work:
一组对比工作:
len(set(the_list)) == 1
Using set
removes all duplicate elements.
使用set删除所有重复的元素。
#5
22
You can convert the list to a set. A set cannot have duplicates. So if all the elements in the original list are identical, the set will have just one element.
你可以把列表转换成一个集合。一个集合不能有重复。如果原始列表中的所有元素都是相同的,那么这个集合就只有一个元素。
if len(sets.Set(input_list)) == 1
// input_list has all identical elements.
#6
10
For what it's worth, this came up on the python-ideas mailing list recently. It turns out that there is an itertools recipe for doing this already:1
不管怎么说,这是最近出现在python-ideas邮件列表中的。事实证明,已经有一个迭代工具的诀窍来实现这一点:1
def all_equal(iterable):
"Returns True if all the elements are equal to each other"
g = groupby(iterable)
return next(g, True) and not next(g, False)
Supposedly it performs very nicely and has a few nice properties.
据说它的性能非常好,并且有一些不错的性能。
- Short-circuits: It will stop consuming items from the iterable as soon as it finds the first non-equal item.
- 短路:当它发现第一个不相等的项时,它将停止从可迭代项中消费项。
- Doesn't require items to be hashable.
- 不需要可洗的东西。
- It is lazy and only requires O(1) additional memory to do the check.
- 它是惰性的,只需要O(1)额外的内存来完成检查。
1In other words, I can't take the credit for coming up with the solution -- nor can I take credit for even finding it.
换句话说,我不能因为提出了解决方案而受到赞扬,甚至我也不能因为找到了解决方案而受到赞扬。
#7
9
This is another option, faster than len(set(x))==1
for long lists (uses short circuit)
这是另一个选项,比len(set(x))= 1要快(使用短路)
def constantList(x):
return x and [x[0]]*len(x) == x
#8
4
This is a simple way of doing it:
这是一种简单的方法:
result = mylist and all(mylist[0] == elem for elem in mylist)
This is slightly more complicated, it incurs function call overhead, but the semantics are more clearly spelled out:
这有点复杂,它会导致函数调用开销,但是语义更清楚地说明了:
def all_identical(seq):
if not seq:
# empty list is False.
return False
first = seq[0]
return all(first == elem for elem in seq)
#9
3
Doubt this is the "most Pythonic", but something like:
怀疑这是“最符合python语言的”,但是类似:
>>> falseList = [1,2,3,4]
>>> trueList = [1, 1, 1]
>>>
>>> def testList(list):
... for item in list[1:]:
... if item != list[0]:
... return False
... return True
...
>>> testList(falseList)
False
>>> testList(trueList)
True
would do the trick.
就可以做到。
#10
3
Convert the list into the set and then find the number of elements in the set. If the result is 1, it has identical elements and if not, then the elements in the list are not identical.
将列表转换为集合,然后找到集合中元素的数量,如果结果是1,它有相同的元素,如果不是,那么列表中的元素就不相同。
list1 = [1,1,1]
len(set(list1))
>1
list1 = [1,2,3]
len(set(list1)
>3
#11
2
I'd do:
我想做的事:
not any((x[i] != x[i+1] for i in range(0, len(x)-1)))
as any
stops searching the iterable as soon as it finds a True
condition.
当any停止搜索iterable时,只要它找到一个真实的条件。
#12
2
If you're interested in something a little more readable (but of course not as efficient,) you could try:
如果你对可读性强一点的东西感兴趣(当然不是那么高效),你可以试试:
def compare_lists(list1, list2):
if len(list1) != len(list2): # Weed out unequal length lists.
return False
for item in list1:
if item not in list2:
return False
return True
a_list_1 = ['apple', 'orange', 'grape', 'pear']
a_list_2 = ['pear', 'orange', 'grape', 'apple']
b_list_1 = ['apple', 'orange', 'grape', 'pear']
b_list_2 = ['apple', 'orange', 'banana', 'pear']
c_list_1 = ['apple', 'orange', 'grape']
c_list_2 = ['grape', 'orange']
print compare_lists(a_list_1, a_list_2) # Returns True
print compare_lists(b_list_1, b_list_2) # Returns False
print compare_lists(c_list_1, c_list_2) # Returns False
#13
2
Regarding using reduce()
with lambda
. Here is a working code that I personally think is way nicer than some of the other answers.
关于对lambda使用reduce()。这里有一个我个人认为比其他答案更好的工作代码。
reduce(lambda x, y: (x[1]==y, y), [2, 2, 2], (True, 2))
Returns a truple where the first value is the boolean if all items are same or not.
返回一个truple,如果所有项都相同或不相同,则第一个值为布尔值。
#14
1
>>> a = [1, 2, 3, 4, 5, 6]
>>> z = [(a[x], a[x+1]) for x in range(0, len(a)-1)]
>>> z
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
# Replacing it with the test
>>> z = [(a[x] == a[x+1]) for x in range(0, len(a)-1)]
>>> z
[False, False, False, False, False]
>>> if False in z : Print "All elements are not equal"
#15
1
def allTheSame(i):
j = itertools.groupby(i)
for k in j: break
for k in j: return False
return True
Works in Python 2.4, which doesn't have "all".
适用于Python 2.4,它没有“全部”。
#16
1
Check if all elements equal to the first.
检查所有元素是否都等于第一个元素。
np.allclose(array, array[0])
np。allclose(数组,数组[0])
#17
1
Can use map and lambda
可以使用map和lambda吗
lst = [1,1,1,1,1,1,1,1,1]
print all(map(lambda x: x == lst[0], lst[1:]))
#18
1
Change the list to a set. Then if the size of the set is only 1, they must have been the same.
将列表更改为一个集合。如果集合的大小只有1,那么它们一定是相同的。
if len(set(my_list)) == 1:
#19
0
You can do:
你能做什么:
reduce(and_, (x==yourList[0] for x in yourList), True)
It is fairly annoying that python makes you import the operators like operator.and_
. As of python3, you will need to also import functools.reduce
.
python让您导入操作符(例如operator.and_)是相当烦人的。对于python3,您还需要导入函数。reduce。
(You should not use this method because it will not break if it finds non-equal values, but will continue examining the entire list. It is just included here as an answer for completeness.)
(您不应该使用这个方法,因为如果它发现不相等的值,它不会中断,而是将继续检查整个列表。它只是作为完整性的答案包含在这里)
#20
0
lambda lst: reduce(lambda a,b:(b,b==a[0] and a[1]), lst, (lst[0], True))[1]
The next one will short short circuit:
下一个将短路:
all(itertools.imap(lambda i:yourlist[i]==yourlist[i+1], xrange(len(yourlist)-1)))