问题:检查列表中的所有元素是否相同
我需要以下功能:
输入:alist
输出:
True
如果输入列表中的所有元素使用标准相等运算符求值彼此相等; False
除此以外。
性能:当然,我不希望产生任何不必要的开销。
我认为最好:
但是我不确定最Pythonic的方法是什么。
缺少短路功能只会损害早期输入不相等的长输入(超过50个元素)。如果这种情况经常发生(频率取决于列表的长度),则需要短路。最好的短路算法似乎是@KennyTM checkEqual1
。但是,它为此付出了巨大的代价:
- 性能几乎是同类产品的20倍
- 短名单上的性能提高了2.5倍
如果没有出现早期输入不相等的长输入(或发生的次数很少),则不需要短路。然后,到目前为止最快的是@Ivo van der Wijk解决方案。
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.
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:
- up to 20x in performance nearly-identical lists
- up to 2.5x in performance on short lists
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.
回答 0
通用方法:
def checkEqual1(iterator):
iterator = iter(iterator)
try:
first = next(iterator)
except StopIteration:
return True
return all(first == rest for rest in iterator)
单线:
def checkEqual2(iterator):
return len(set(iterator)) <= 1
也是单线的:
def checkEqual3(lst):
return lst[1:] == lst[:-1]
这三个版本之间的区别在于:
- 在
checkEqual2
内容中必须是可哈希的。 checkEqual1
并且checkEqual2
可以使用任何迭代器,但checkEqual3
必须接受序列输入,通常是列表或元组之类的具体容器。 checkEqual1
发现差异后立即停止。 - 由于
checkEqual1
包含更多的Python代码,因此当许多项目在开始时相等时效率较低。 - 由于
checkEqual2
并checkEqual3
始终执行O(N)复制操作,因此,如果您的大多数输入将返回False,则它们将花费更长的时间。 - 对于
checkEqual2
,checkEqual3
很难适应从a == b
到的比较a is b
。
timeit
结果,对于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 = []
我们得到
| 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 |
注意:
# http://stackoverflow.com/q/3844948/
def checkEqualIvo(lst):
return not lst or lst.count(lst[0]) == len(lst)
# http://stackoverflow.com/q/3844931/
def checkEqual6502(lst):
return not lst or [lst[0]]*len(lst) == lst
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. checkEqual1
and checkEqual2
can use any iterators, but checkEqual3
must take a sequence input, typically concrete containers like a list or tuple. checkEqual1
stops as soon as a difference is found. - Since
checkEqual1
contains more Python code, it is less efficient when many of the items are equal in the beginning. - Since
checkEqual2
and checkEqual3
always perform O(N) copying operations, they will take longer if most of your input will return False. - For
checkEqual2
and checkEqual3
it’s harder to adapt comparison from a == b
to a is b
.
timeit
result, for Python 2.7 and (only s1, s4, s7, s9 should return 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://stackoverflow.com/q/3844948/
def checkEqualIvo(lst):
return not lst or lst.count(lst[0]) == len(lst)
# http://stackoverflow.com/q/3844931/
def checkEqual6502(lst):
return not lst or [lst[0]]*len(lst) == lst
回答 1
比对序列(不是可迭代对象)使用set()更快的解决方案是仅对第一个元素进行计数。这假设列表是非空的(但是检查起来很麻烦,并自己决定结果应该在空列表中)
x.count(x[0]) == len(x)
一些简单的基准:
>>> 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
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)
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
回答 2
最简单,最优雅的方法如下:
all(x==myList[0] for x in myList)
(是的,这甚至适用于空列表!这是因为这是python具有惰性语义的少数情况之一。)
关于性能,这将尽早失败,因此它是渐近最佳的。
The simplest and most elegant way is as follows:
all(x==myList[0] for x in myList)
(Yes, this even works with the empty list! This is because this is one of the few cases where python has lazy semantics.)
Regarding performance, this will fail at the earliest possible time, so it is asymptotically optimal.
回答 3
一组比较工作:
len(set(the_list)) == 1
使用set
删除所有重复的元素。
A set comparison work:
len(set(the_list)) == 1
Using set
removes all duplicate elements.
回答 4
您可以将列表转换为集合。集合不能重复。因此,如果原始列表中的所有元素都相同,则该集合将只有一个元素。
if len(sets.Set(input_list)) == 1
// input_list has all identical elements.
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.
回答 5
对于它的价值,它最近出现在python-ideas邮件列表中。事实证明,已经有一个itertools方法可以做到这一点: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)
据说它的性能非常好,并且具有一些不错的属性。
- 短路:一旦找到第一个不等项,它将立即停止消耗可迭代项中的项。
- 不需要项目是可哈希的。
- 它是惰性的,仅需要O(1)额外的内存来执行检查。
1换句话说,我不能因提出解决方案而功不可没-甚至找不到它也不能功劳。
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
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.
1In other words, I can’t take the credit for coming up with the solution — nor can I take credit for even finding it.
回答 6
这是两种简单的方法
使用set()
将列表转换为集合时,将删除重复的元素。因此,如果转换后的集合的长度为1,则意味着所有元素都相同。
len(set(input_list))==1
这是一个例子
>>> a = ['not', 'the', 'same']
>>> b = ['same', 'same', 'same']
>>> len(set(a))==1 # == 3
False
>>> len(set(b))==1 # == 1
True
使用all()
这会将输入列表的第一个元素与列表中的所有其他元素进行比较(等效)。如果相等,则返回True,否则返回False。
all(element==input_list[0] for element in input_list)
这是一个例子
>>> a = [1, 2, 3, 4, 5]
>>> b = [1, 1, 1, 1, 1]
>>> all(number==a[0] for number in a)
False
>>> all(number==b[0] for number in b)
True
PS如果要检查整个列表是否等效于某个值,则可以在input_list [0]中设置该值。
Here are two simple ways of doing this
using set()
When converting the list to a set, duplicate elements are removed. So if the length of the converted set is 1, then this implies that all the elements are the same.
len(set(input_list))==1
Here is an example
>>> a = ['not', 'the', 'same']
>>> b = ['same', 'same', 'same']
>>> len(set(a))==1 # == 3
False
>>> len(set(b))==1 # == 1
True
using all()
This will compare (equivalence) the first element of the input list to every other element in the list. If all are equivalent True will be returned, otherwise False will be returned.
all(element==input_list[0] for element in input_list)
Here is an example
>>> a = [1, 2, 3, 4, 5]
>>> b = [1, 1, 1, 1, 1]
>>> all(number==a[0] for number in a)
False
>>> all(number==b[0] for number in b)
True
P.S If you are checking to see if the whole list is equivalent to a certain value, you can suibstitue the value in for input_list[0].
回答 7
这是另一种选择,比len(set(x))==1
长列表(使用短路)快
def constantList(x):
return x and [x[0]]*len(x) == x
This is another option, faster than len(set(x))==1
for long lists (uses short circuit)
def constantList(x):
return x and [x[0]]*len(x) == x
回答 8
这是一种简单的方法:
result = mylist and all(mylist[0] == elem for elem in mylist)
这稍微复杂一点,但会产生函数调用开销,但语义会更清楚地说明:
def all_identical(seq):
if not seq:
# empty list is False.
return False
first = seq[0]
return all(first == elem for elem in seq)
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
检查所有元素是否等于第一个。
np.allclose(array, array[0])
Check if all elements equal to the first.
np.allclose(array, array[0])
回答 10
怀疑这是“最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
会成功的
Doubt this is the “most Pythonic”, but something like:
>>> 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.
回答 11
如果您对可读性更高(但当然不那么有效)感兴趣,可以尝试:
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
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
回答 12
将列表转换为集合,然后找到集合中的元素数。如果结果为1,则其元素相同,如果不相同,则列表中的元素不相同。
list1 = [1,1,1]
len(set(list1))
>1
list1 = [1,2,3]
len(set(list1)
>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.
list1 = [1,1,1]
len(set(list1))
>1
list1 = [1,2,3]
len(set(list1)
>3
回答 13
关于reduce()
与一起使用lambda
。这是一个我个人认为比其他答案更好的工作代码。
reduce(lambda x, y: (x[1]==y, y), [2, 2, 2], (True, 2))
返回一个元组,如果所有项目相同或不同,则第一个值为布尔值。
Regarding using reduce()
with lambda
. Here is a working code that I personally think is way nicer than some of the other answers.
reduce(lambda x, y: (x[1]==y, y), [2, 2, 2], (True, 2))
Returns a tuple where the first value is the boolean if all items are same or not.
回答 14
我会做:
not any((x[i] != x[i+1] for i in range(0, len(x)-1)))
因为any
一旦找到True
条件就停止搜索可迭代对象。
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.
回答 15
>>> 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"
>>> 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"
回答 16
def allTheSame(i):
j = itertools.groupby(i)
for k in j: break
for k in j: return False
return True
在没有“ all”的Python 2.4中工作。
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”.
回答 17
可以使用地图和lambda
lst = [1,1,1,1,1,1,1,1,1]
print all(map(lambda x: x == lst[0], lst[1:]))
Can use map and lambda
lst = [1,1,1,1,1,1,1,1,1]
print all(map(lambda x: x == lst[0], lst[1:]))
回答 18
或使用diff
numpy的方法:
import numpy as np
def allthesame(l):
return np.all(np.diff(l)==0)
并调用:
print(allthesame([1,1,1]))
输出:
True
Or use diff
method of numpy:
import numpy as np
def allthesame(l):
return np.all(np.diff(l)==0)
And to call:
print(allthesame([1,1,1]))
Output:
True
回答 19
或者使用numpy的diff方法:
import numpy as np
def allthesame(l):
return np.unique(l).shape[0]<=1
并调用:
print(allthesame([1,1,1]))
输出:
真正
Or use diff method of numpy:
import numpy as np
def allthesame(l):
return np.unique(l).shape[0]<=1
And to call:
print(allthesame([1,1,1]))
Output:
True
回答 20
你可以做:
reduce(and_, (x==yourList[0] for x in yourList), True)
python使您像那样导入运算符是很烦人的operator.and_
。从python3开始,您还需要import functools.reduce
。
(您不应该使用此方法,因为如果找到不相等的值,它将不会中断,但是会继续检查整个列表。此处仅作为完整性的答案。)
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
.
(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.)
回答 21
lambda lst: reduce(lambda a,b:(b,b==a[0] and a[1]), lst, (lst[0], True))[1]
下一个将短路短路:
all(itertools.imap(lambda i:yourlist[i]==yourlist[i+1], xrange(len(yourlist)-1)))
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)))
回答 22
将列表更改为一组。然后,如果集合的大小仅为1,则它们必须相同。
if len(set(my_list)) == 1:
Change the list to a set. Then if the size of the set is only 1, they must have been the same.
if len(set(my_list)) == 1:
回答 23
还有一个纯Python递归选项:
def checkEqual(lst):
if len(lst)==2 :
return lst[0]==lst[1]
else:
return lst[0]==lst[1] and checkEqual(lst[1:])
但是由于某种原因,它在某些情况下比其他选择要慢两个数量级。从C语言的心态来看,我期望这会更快,但事实并非如此!
另一个缺点是Python中存在递归限制,在这种情况下需要对其进行调整。例如使用this。
There is also a pure Python recursive option:
def checkEqual(lst):
if len(lst)==2 :
return lst[0]==lst[1]
else:
return lst[0]==lst[1] and checkEqual(lst[1:])
However for some reason it is in some cases two orders of magnitude slower than other options. Coming from C language mentality, I expected this to be faster, but it is not!
The other disadvantage is that there is recursion limit in Python which needs to be adjusted in this case. For example using this.
回答 24
您可以.nunique()
用来查找列表中唯一项目的数量。
def identical_elements(list):
series = pd.Series(list)
if series.nunique() == 1: identical = True
else: identical = False
return identical
identical_elements(['a', 'a'])
Out[427]: True
identical_elements(['a', 'b'])
Out[428]: False
You can use .nunique()
to find number of unique items in a list.
def identical_elements(list):
series = pd.Series(list)
if series.nunique() == 1: identical = True
else: identical = False
return identical
identical_elements(['a', 'a'])
Out[427]: True
identical_elements(['a', 'b'])
Out[428]: False
回答 25
您可以使用set
。它将设置并删除重复的元素。然后检查其元素是否超过1个。
if len(set(your_list)) <= 1:
print('all ements are equal')
例:
>>> len(set([5, 5])) <= 1
True
you can use set
. It will make a set and remove repetitive elements. Then check that it has no more than 1 element.
if len(set(your_list)) <= 1:
print('all ements are equal')
Example:
>>> len(set([5, 5])) <= 1
True
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。