wtfpython icon indicating copy to clipboard operation
wtfpython copied to clipboard

Element-wise comparison for lists

Open parautenbach opened this issue 6 months ago • 3 comments

# let's validate some rgb values
In [1]: [0, 0, 0] <= [255, 123, 5] <= [255, 255, 255]
Out[1]: True

# 256 > 255, so we expect false
In [2]: [0, 0, 0] <= [256, 123, 5] <= [255, 255, 255]
Out[2]: False

# how about a negative value? wait, what!?
In [3]: [0, 0, 0] <= [255, 123, -5] <= [255, 255, 255]
Out[3]: True

# ok, so a single element list works
In [8]: [0] <= [-5] <= [255]
Out[8]: False

# let's avoid the chaining: still no
In [13]: ([0, 0, 0] <= [255, 123, -5]) and ([255, 123, -5] <= [255, 255, 255])
Out[13]: True

# put the negative element first: now it "works"
In [21]: [0, 0, 0] <= [-5, 123, 2555] <= [255, 255, 255]
Out[21]: False

It seems that Python will only compare the first elements of each list and continue.

parautenbach avatar Jan 02 '24 11:01 parautenbach

The same result is obtained in JavaScript.

> [0, 0, 0] <= [255, 123, 5] && [255, 123, 5] <= [255, 255, 255]
true
> [0, 0, 0] <= [256, 123, 5] && [256, 123, 5] <= [255, 255, 255]
false
> [0, 0, 0] <= [255, 123, -5] && [255, 123, -5] <= [255, 255, 255]
true
> [0] <= [-5] && [-5] <= [255]
false
> ([0, 0, 0] <= [255, 123, -5]) && ([255, 123, -5] <= [255, 255, 255])
true
> [0, 0, 0] <= [-5, 123, 2555] && [-5, 123, 2555] <= [255, 255, 255]
false

shiracamus avatar Jan 02 '24 11:01 shiracamus

Python uses the lexicographic order, same as C++ and most languages really.

lezcano avatar Jan 03 '24 17:01 lezcano

As shiracamus and lezcano have already mentioned, pretty much every other language uses the same implementation as it is consistent with the general idea of lexicographical ordering. If you really want you could create a custom class and maybe override how the comparison operators work for specific use case.

class CustomList(list):
    def __le__(self, other):
        return all(x <= y for x, y in zip(self, other))

    def __ge__(self, other):
        return all(x >= y for x, y in zip(self, other))

    def __lt__(self, other):
        return all(x < y for x, y in zip(self, other))

    def __gt__(self, other):
        return all(x > y for x, y in zip(self, other))

def test_custom_list():
    assert CustomList([0, 0, 0]) <= CustomList([255, 123, 5]) <= CustomList([255, 255, 255])
    assert not CustomList([0, 0, 0]) <= CustomList([256, 123, 5]) <= CustomList([255, 255, 255])
    assert CustomList([0, 0, 0]) <= CustomList([255, 123, -5]) <= CustomList([255, 255, 255])
    assert not CustomList([0]) <= CustomList([-5]) <= CustomList([255])
    assert not CustomList([0, 0, 0]) <= CustomList([-5, 123, 2555]) <= CustomList([255, 255, 255])

# You can run these test cases
test_custom_list()

In this example, I created a Custom class that inherits from the built-in list class and overrides the less than or equal (le), greater than or equal (ge), less than (lt), and greater than (gt) comparison methods.

pavanbadempet avatar Jan 30 '24 10:01 pavanbadempet