Are all items in list the same?

Cameron Simpson cs at cskk.id.au
Mon Jan 7 20:10:14 EST 2019


On 07Jan2019 17:14, bvdp <bob at mellowood.ca> wrote:
>I need to see if all the items in my list are the same. I was using set()
>for this, but that doesn't work if items are themselves lists. So, assuming
>that a is a list of some things, the best I've been able to come up with it:
>
>    if a.count( targ ) == len(a):
>
>I'm somewhat afraid that this won't scale all that well. Am I missing
>something?

This can be inefficient and probably will be in real life.

For the "true" case (all elements == targ), this is ok - you cannot know 
they are all equal without examining every element.

But it is very inefficient for the false case (not all items == targ) 
because it compares all the items, even if some items have already 
compared unequal. (It compares them all because it must _count_ the 
later equal items, regardless of how many earlier items are unequal).

Because this feels like a homework exercise, we generally offer advice 
and suggestions, thus the nature of the discussion which follows.

The immediate approach is to not use .count and instead just write a 
"for" look which compares each array item in turn, and importantly 
_breaks out of the loop_ as soon as it sees an unequal value. You might 
set a flag (Boolean value) to True, then test the elements: when one is 
unequal, set the flag to False and break from the loop. After the loop, 
the flag will indicate whether all were equal. Give that a try.

_After_ that, once you understand the logic, you could consider the 
built functions Python comes with.

You might look at the builtin "all" function; its help is like this:

    >>> help(all)
    Help on built-in function all in module builtins:

    all(iterable, /)
        Return True if bool(x) is True for all values x in the iterable.

        If the iterable is empty, return True.

It doesn't say so, but it will return as soon as it hits a false item 
from the iterable. So you need to take your list "a" and produce an 
iterable of True or False depending on whether the element is equal to 
your test argument.

The tricky bit is to make "iterable" lazy: an actual iterator which only 
yields values as required. For example, this list comprehension:

  [ elem == targ for elem in a ]

computes the _complete_ list of true/false values and returns a list. So 
passing that to all() does not improve efficiency because for a long 
list it still examines every element even if an early element is 
unequal.

Instead you should look at writing a generator expression or function,
which all() can iterate over: these things only advance as they are 
asked for a value, and so if all() stops early, the generator also does 
not run to completion and so does not uselessly examine the entire list.

Cheers,
Cameron Simpson <cs at cskk.id.au>



More information about the Python-list mailing list