103

In some of my code I put a series of objects in a list and I build an additional list out of their attributes, which is a string. I need to determine if all the items in this second list have the exact same value, without knowing beforehand which value it is, and return a bool so that I can do different things in my code depending on the result.

I can't know the names of the properties beforehand, that is why I'm trying to make something as generic as possible.

To make the example clear, an ideal function, called "all_same" would work like this:

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

I was thinking of making a list of unique elements and then check if its length is 1, but I'm not sure if it's the most elegant solution out there.

Einar
  • 4,727
  • 7
  • 49
  • 64
  • Just realized that I asked the same question here: http://stackoverflow.com/questions/3844801/check-if-all-elements-in-a-list-are-identical. How do I link these two questions? – max Oct 03 '10 at 18:00
  • 1
    Heh, first question I've seen where an earlier question is the duplicate. Time does sometimes work in reverse. – wheaties Aug 31 '16 at 02:14
  • The title of this one sounds like the asker wants to check *identity* (`a is b`), not *equality* (`a == b`) – Nick T Jun 20 '19 at 17:29

7 Answers7

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

Example:

>>> 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
FogleBird
  • 74,300
  • 25
  • 125
  • 131
  • 71
    `len(set(items)) == 1` is faster. – JulienD May 19 '15 at 09:24
  • 1
    This answer has a few shortcommings: it only works with indexables and with equality (and no identity). Hence a slightly improved version: 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) This will work with unsized iterable such as generators, allow you to specify what "is the same" mean and what to do on an empty value. – Bite code Mar 06 '16 at 18:11
  • 1
    @e-satis improve the answer with that version. – salparadise Jul 22 '17 at 07:02
  • This will raise a `KeyError` if your list is empty, when it should return `True`. – Boris Verkhovskiy Nov 01 '20 at 17:20
63

You could cheat and use set:

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

or you could use:

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

or if you're dealing with an iterable instead of a list:

def all_same( iterable ):
    it_copy = tee( iterable, 1 )
    return len( set( it_copy) ) == 1
wheaties
  • 35,646
  • 15
  • 94
  • 131
  • The set would have just one item, the list would have N. – FogleBird Sep 24 '10 at 14:18
  • 1
    You could use generator expression in the 2nd code. `all(x == items[0] for x in items)`. – kennytm Sep 24 '10 at 14:21
  • 15
    len(set(items)) == 1 definitely most idiomatic. – Beni Cherniavsky-Paskin Sep 24 '10 at 15:05
  • It is also much faster: `a = ["a"]*100; a[53]="b"`. `%timeit len(set(a)) == 1` --> 2.83us per loop. `%timeit all(x==a[0] for x in a)` --> 7.78us per loop. – JulienD May 19 '15 at 09:22
  • @muraveill What machine did you use and can you reproduce those results? I get the opposite relative ordering on both machines I could try: the `all()` approach is about 3 times faster than the `set()` approach. – jw013 Jan 13 '16 at 01:46
  • It was an old MacBook Air. I did it again on a MacBook Pro: `len(set(a))`: 1.81 µs per loop, `all(x==a[0] for x in a)`: 5.26 µs per loop. – JulienD Jan 13 '16 at 08:01
12

Best way to do this is to use Python sets.You need to define all_same like this:

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

Test:

>>> 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
Brandon Yarbrough
  • 37,021
  • 23
  • 116
  • 145
rezakamalifard
  • 1,289
  • 13
  • 24
10

I originally interpreted you to be testing identity ("the same item"), but you're really testing equality ("same value"). (If you were testing identity, use is instead of ==.)

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)

The above works on any iterable, not just lists, otherwise you could use:

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

(But, IMHO, you might as well use the general version—it works perfectly fine on lists.)

  • +1 I'll have to remember that recipe. – aaronasterling Sep 24 '10 at 14:30
  • @katrielalex: Then you have to try/except for StopIteration; at that point, it's equivalent behavior and the same length. –  Sep 24 '10 at 14:48
  • 1
    I prefer `try: first = next(it) except StopIteration: return True` -- I think the flow is clearer -- but same difference, really. – Katriel Sep 24 '10 at 14:49
  • @Roger: sorry, noticed that and deleted too late. Indeed! =) – Katriel Sep 24 '10 at 14:50
  • I like this solution. Even if the OP asked only for lists, generators are so pervasive now in Python that it's better not to assume that the input is a sequence. Note that you can simplify it a bit with Python >= 2.6: first = next(it, None) – tokland Sep 24 '10 at 15:00
  • @tokland: Doesn't work, what if you want to pass `[None, 42]` to the function? (You can use a sentinel object that is only ever used in this function, but way more hassle than it's worth here.) –  Sep 24 '10 at 15:14
  • @Roger: if you pass [None, 42] you get False, as you'd expect. Note that the sentinel is never actually used if the iterable is empty. – tokland Sep 24 '10 at 16:06
  • @tokland: I know the sentinel is never used, that's why I placed None first: you can't tell if the None you get is from the list or from the second param. Could you post code? (A new answer? Since it would also answer this question.) Obviously we're imagining different things. –  Sep 24 '10 at 16:08
  • @Roger: There is my answer, I think you'll recognize the last assert ;-) you are right that usually sentinels cannot be a potential element in the input, but it does not apply here. Or am I missing something? – tokland Sep 24 '10 at 16:22
  • (response in comment on [that answer](http://stackoverflow.com/questions/3787908/python-determine-if-all-items-of-a-list-are-the-same-item/3789000#3789000), posted before asked! :P) –  Sep 24 '10 at 16:28
5

This works both for sequences and iterables:

def all_same(items):
  it = iter(items)
  first = next(it, None)
  return all(x == first for x in it)
tokland
  • 66,169
  • 13
  • 144
  • 170
  • 1
    Ah, I was imagining you'd check `first is None` instead of letting this fall-through. It does give the right result, but I prefer to treat this an error/"exceptional circumstance" instead of depending on later code to silently do the right thing. –  Sep 24 '10 at 16:21
  • I know I am very unpythonic in this opinion, but I don't like that a pretty single line turns into four because I have to catch an exception (I speak in general, you used a for/break in you answer). Yeah, I known about EAFP, but still, if I can avoid it... Thanks for the +1, though :-) – tokland Sep 24 '10 at 16:31
2

This is likely to be faster if you know values are in a list.

def all_same(values):
    return values.count(values[0]) == len(values)
Jonas K
  • 4,215
  • 2
  • 24
  • 25
-1

I created this snippet of code for that same issue after thinking it over. I'm not exactly sure if it works for every scenario though.

def all_same(list):
    list[0]*len(list) == list
  • 1
    I'm afraid this doesn't work at all. E.g. `test_list=[1, 1]` and `all_same(test_list)` returns `False` because `test_list[0] = 1` and `len(test_list) = 2` so the results is just `1 * 2 = 2`. Then you test `2 == test_list`, which is not True. – n1k31t4 Nov 07 '17 at 06:20