Check if all elements in a list are identical
algorithm, comparison, python
Solution
Use `itertools.groupby` (see the `itertools` recipes):
from itertools import groupby
def all_equal(iterable):
g = groupby(iterable)
return next(g, True) and not next(g, False)
or without `groupby`:
def all_equal(iterator):
iterator = iter(iterator)
try:
first = next(iterator)
except StopIteration:
return True
return all(first == x for x in iterator)
There are a number of alternative one-liners you might consider:
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
But they have some downsides, namely:
- `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.
On Python 3.9, using `perfplot`, we get these timings (lower `Runtime [s]` is better):
Problem
I need a function which takes in a `list` and outputs `True` if all elements in the input list evaluate as equal to each other using the standard equality operator and `False` otherwise. I feel it would be best to iterate through the list comparing adjacent elements and then `AND` all the resulting Boolean values. But I'm not sure what's the most Pythonic way to do that.