Вопрос

I was asked if it was possible to compare two (say) lists without invoking operators, to determine if they were the same (or rather, contained the same elements).

I first entertained using

x in y

before I realised that it would not care for order, but for mere presence. Of course, if the lists were to contain purely numbers it would be trivial to do a modulus test or so, but lists can contain strings. (is didn't work either, but I didn't really expect it to, considering it tests identity...)

So I was wondering if it's (even) possible to pull off equality tests without using operators (==, !=)?

It was a mere rhetorical question, but it's been gnawing at me for some time and I've rather given up trying to solve it myself with my not-very extensive python knowledge.

Это было полезно?

Решение

Sure it is, just bypass the operators and go straight for the __eq__ special method:

>>> x = [1, 2, 3]
>>> y = [1, 2, 3]
>>> x.__eq__(y)
True
>>> z = [42]
>>> x.__eq__(z)
False

You can also use the operator module:

>>> import operator
>>> operator.eq(x, y)
True
>>> operator.eq(x, z)
False

In Python 2, you could use looping with any() and cmp(), with itertools.izip_longest() to make sure we don't ignore uneven lengths:

>>> from itertools import izip_longest
>>> not any(cmp(i, j) for i, j in izip_longest(x, y, fillvalue=object()))
True
>>> not any(cmp(i, j) for i, j in izip_longest(x, z, fillvalue=object()))
False

This works because cmp() returns 0 for values that are equal. any() returns False only if all results are false (e.g. 0).

Hell, go straight for cmp() without looping:

>>> not cmp(x, y)
True
>>> not cmp(x, z)
False

For Python 3 you'd have to create your own cmp() function, perhaps using .__lt__ and .__gt__ if you want to avoid the < and > operators too.

For lists with only integers, you can forgo the cmp() function and go straight to subtraction; let's use map() here and include the list lengths:

>>> not (len(x) - len(y)) and not any(map(lambda i, j: i - j, x, y))
True
>>> not (len(x) - len(z)) and not any(map(lambda i, j: i - j, x, z))
False

This works because map() zips up the values in the lists and passes these pairs to the first argument, a callable. That subtracts the values and only if the integers are equal do we get all 0 values and any() returns False.

Другие советы

Apart from Martijn Pieters's answer, i could think of following options:

using XOR:

x = [1, 2, 3]
y = [1, 2, 3]
result = "list equal"
if len(x)-len(y):
    result = "list not equal"
else:
    for i,j in zip(x,y):
        if i ^ j: 
            result = "list is not equal"
            break
print result

Using set:

if set(x).difference(set(y)):
    print "list not equal"
else:
    print "list equal"
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top