Mannix
Mannix

Reputation: 431

Python boolean operations on lists - inconsistent results

Suppose I have two lists:

>>> y
[False, False, True, False, True, False, False, True, False, True, False, False]
>>> z
[False, True, True, True, True, True, False, False, False, False, False, True]

Then I do the following:

>>> y or z
[False, False, True, False, True, False, False, True, False, True, False, False]
>>> z or y
[False, True, True, True, True, True, False, False, False, False, False, True]

Shouldn't the correct answer be as shown below?

[False, True, True, True, True, True, False, True, False, True, False, True]

I also get incorrect answers with and:

>>> y and z
[False, True, True, True, True, True, False, False, False, False, False, True]
>>> z and y
[False, False, True, False, True, False, False, True, False, True, False, False]

I tested 1s and 0s with odd results:

>>> y=[0,0,0,0,0]
>>> z=[1,1,1,1,1]
>>> y or z
[0, 0, 0, 0, 0]
>>> z or y
[1, 1, 1, 1, 1]
>>> y and z
[1, 1, 1, 1, 1]
>>> z and y
[0, 0, 0, 0, 0]

What am I doing incorrectly?

Upvotes: 2

Views: 84

Answers (2)

JkShaw
JkShaw

Reputation: 1947

The correct approach for or operation:

[a or b for a, b in zip(y, z)]

The correct approach for and operation:

[a and b for a, b in zip(y, z)]

None, False, 0, '', (), [], {} and few more (mentioned here -> Truth Value Testing) are considered False.

here's some example:

[] is False, [False] is True since its not empty, check using bool([False])

>>> [] and [False]
[]
>>> bool([] and [False])
False

[] is False, [False] is True, hence Here True

>>> [] or [False]
[False]
>>> bool([] or [False])
True

Upvotes: 1

Tom Dalton
Tom Dalton

Reputation: 6190

y or z doesn't behave how you think it does, on the individual elements. Instead, it evaluates the 'truthiness' of the first argument (y). Since y is a non-empty list, it evaluates to true. The overall statement then evaluates to y.

Similarly, z or y first looks to see if z is truthy (which it is, because it's a non empty list). Thus the statement evaluates to z without ever looking at y or the elements within it.

Here are some clearer examples:

>>> [1,2,3,4] or [5,6,7,8]
[1, 2, 3, 4]
>>> ['this','is','a','list'] or ['and','here','is','another']
['this', 'is', 'a', 'list']

An empty list evaluates as 'false-y', so in this care, the right hand list is the value of the statement:

>>> [] or ['and','here','is','another']
['and', 'here', 'is', 'another']

Swapping the order of the lists shows that the first one to evaluate as true will be the result:

>>> ['and','here','is','another'] or ['this','is','a','list']
['and', 'here', 'is', 'another']

To achieve what you want, you could do a list comprehension like

[
    y_item or z_item
    for y_item, z_item
    in zip(y, z)
]

Upvotes: 6

Related Questions