`itertools.all_equal`

I am not .

I’m not sure why I’m bothering to reply, I can’t tell if this is some kind of trolling or if you’re just really confused or something because you contradicted yourself multiple times already.

First you said that I had suggested adding

all(map(operator.eq, iterable[1:], iterable[:-1]))

to the Python code somewhere as an implementation of all_equal. I did not suggest this.

Then later, you denied doing so.

Seriously? What is going on here?

1 Like

Not true. I didn’t.

The current recipe is:

def all_equal(iterable, key=None):
    "Returns True if all the elements are equal to each other."
    return len(take(2, groupby(iterable, key))) <= 1

I don’t think that’s unreadable, and I don’t believe it’s slow. Of course there may be real code where a proper benchmark would find a strictly superior alternative, but I believe we are at the point where a microbenchmark isn’t particularly relevant.

If there’s a nice primitive that would make this code more readable, equally performant, and enable other common patterns, that sounds like a great candidate for a third-party library to prove out.

5 Likes

Can you explain it using 1 sentence?

In fairness, the other recipe which I have seen is far worse.

next(g, True) and not next(g, False)

Try explaining that in a single sentence.

At least if you know what groupby does, then the code you posted above is fairly obvious. However you have to know what groupby does as a prerequisite. Since groupby isn’t part of the standard library, this is some non-trivial amount of work you have to do to figure it out.

The main issue I take with it is the operations of checking for equality has nothing to do with grouping. It just so happens to be that if you group objects together you can use the output of this to prove by contradiction that all the elements are not equal.

Groupby must be performing an __eq__ check in order for it to work. So why not just do the __eq__ check?

I hope it doesn’t appear that I am being pedantic here. We like Python for its simplicity and “one obvious way of doing things”. This itertools recipe (the one I posted) is anything but the most obvious solution.

I agree the above alternative is better.

It is.

The grouping is done by checking for equality.

And quoting Raymond about all_equal (or its old recipe version, not sure):

Which is perfectly fine and normal. Do you also dislike all’s equivalent code

def all(iterable):
    for element in iterable:
        if not element:
            return False
    return True

because it’s supposed to check whether all elements are true, but instead checks whether they’re "not* true and doesn’t even check all elements, instead using the first not true element to “prove by contradiction that all the elements are not true”?

2 Likes

I needed this today but I knew my input is going to be strings (which are hashable) so I just did return len(set(myiterable)) == 1