Numpy's logical_or
function takes no more than two arrays to compare. How can I find the union of more than two arrays? (The same question could be asked with regard to Numpy's logical_and
and obtaining the intersection of more than two arrays.)

- 160,171
- 8
- 81
- 157

- 1,507
- 2
- 9
- 4
-
7[`any()`](http://docs.python.org/2/library/functions.html#any) ? – karthikr Dec 11 '13 at 19:35
-
is there a way analagous to any()? – user3074893 Dec 11 '13 at 19:58
-
@user3074893: It's exactly the same issue. You want me to expand my answer? – abarnert Dec 11 '13 at 19:58
9 Answers
If you're asking about numpy.logical_or
, then no, as the docs explicitly say, the only parameters are x1, x2
, and optionally out
:
numpy.
logical_or
(x1, x2[, out]
) =<ufunc 'logical_or'>
You can of course chain together multiple logical_or
calls like this:
>>> x = np.array([True, True, False, False])
>>> y = np.array([True, False, True, False])
>>> z = np.array([False, False, False, False])
>>> np.logical_or(np.logical_or(x, y), z)
array([ True, True, True, False], dtype=bool)
The way to generalize this kind of chaining in NumPy is with reduce
:
>>> np.logical_or.reduce((x, y, z))
array([ True, True, True, False], dtype=bool)
And of course this will also work if you have one multi-dimensional array instead of separate arrays—in fact, that's how it's meant to be used:
>>> xyz = np.array((x, y, z))
>>> xyz
array([[ True, True, False, False],
[ True, False, True, False],
[False, False, False, False]], dtype=bool)
>>> np.logical_or.reduce(xyz)
array([ True, True, True, False], dtype=bool)
But a tuple of three equal-length 1D arrays is an array_like in NumPy terms, and can be used as a 2D array.
Outside of NumPy, you can also use Python's reduce
:
>>> functools.reduce(np.logical_or, (x, y, z))
array([ True, True, True, False], dtype=bool)
However, unlike NumPy's reduce
, Python's is not often needed. For most cases, there's a simpler way to do things—e.g., to chain together multiple Python or
operators, don't reduce
over operator.or_
, just use any
. And when there isn't, it's usually more readable to use an explicit loop.
And in fact NumPy's any
can be used for this case as well, although it's not quite as trivial; if you don't explicitly give it an axis, you'll end up with a scalar instead of an array. So:
>>> np.any((x, y, z), axis=0)
array([ True, True, True, False], dtype=bool)
As you might expect, logical_and
is similar—you can chain it, np.reduce
it, functools.reduce
it, or substitute all
with an explicit axis
.
What about other operations, like logical_xor
? Again, same deal… except that in this case there is no all
/any
-type function that applies. (What would you call it? odd
?)

- 5,520
- 2
- 25
- 38

- 354,177
- 51
- 601
- 671
-
9
-
```reduce``` is no longer an internal function in python 3. Instead use: ```functools.reduce()``` – marvin Sep 03 '19 at 16:20
-
1
-
Seems using functools.reduce is faster than numpy's own reduce. Anyone know why? – Håkon T. Dec 09 '21 at 13:51
In case someone still need this - Say you have three Boolean arrays a
, b
, c
with the same shape, this gives and
element-wise:
a * b * c
this gives or
:
a + b + c
Is this what you want?
Stacking a lot of logical_and
or logical_or
is not practical.

- 912
- 2
- 7
- 19
Building on abarnert's answer for n-dimensional case:
TL;DR: np.logical_or.reduce(np.array(list))

- 4,918
- 3
- 38
- 39
As boolean algebras are both commutative and associative by definition, the following statements or equivalent for boolean values of a, b and c.
a or b or c
(a or b) or c
a or (b or c)
(b or a) or c
So if you have a "logical_or" which is dyadic and you need to pass it three arguments (a, b, and c), you can call
logical_or(logical_or(a, b), c)
logical_or(a, logical_or(b, c))
logical_or(c, logical_or(b, a))
or whatever permutation you like.
Back to python, if you want to test whether a condition (yielded by a function test
that takes a testee and returns a boolean value) applies to a or b or c or any element of list L, you normally use
any(test(x) for x in L)

- 31,997
- 9
- 47
- 87
-
1But Python `or` isn't really boolean `or`, both because it works on values other than `bool`s (returning `a` if `a` is truthy, `b` otherwise), and because it short-circuits (meaning `a or b` may be True, while `b or a` raises an exception). – abarnert Dec 11 '13 at 19:42
-
-
(I'm not sure why people downvoted this, however… the OP seems to be specifically talking about boolean values, which he calls "logical conditions".) – abarnert Dec 11 '13 at 19:43
-
1@abarnert Don't ask me. I am of the opinion that if you get your maths straight (in this case boolean algebras) in the background, a lot of programming issues are easier to solve. – Hyperboreus Dec 11 '13 at 19:45
I use this workaround which can be extended to n arrays:
>>> a = np.array([False, True, False, False])
>>> b = np.array([True, False, False, False])
>>> c = np.array([False, False, False, True])
>>> d = (a + b + c > 0) # That's an "or" between multiple arrays
>>> d
array([ True, True, False, True], dtype=bool)

- 558
- 3
- 7
I've tried the following three different methods to get the logical_and
of a list l of k arrays of size n:
- Using a recursive
numpy.logical_and
(see below) - Using
numpy.logical_and.reduce(l)
- Using
numpy.vstack(l).all(axis=0)
Then I did the same for the logical_or
function. Surprisingly enough, the recursive method is the fastest one.
import numpy
import perfplot
def and_recursive(*l):
if len(l) == 1:
return l[0].astype(bool)
elif len(l) == 2:
return numpy.logical_and(l[0],l[1])
elif len(l) > 2:
return and_recursive(and_recursive(*l[:2]),and_recursive(*l[2:]))
def or_recursive(*l):
if len(l) == 1:
return l[0].astype(bool)
elif len(l) == 2:
return numpy.logical_or(l[0],l[1])
elif len(l) > 2:
return or_recursive(or_recursive(*l[:2]),or_recursive(*l[2:]))
def and_reduce(*l):
return numpy.logical_and.reduce(l)
def or_reduce(*l):
return numpy.logical_or.reduce(l)
def and_stack(*l):
return numpy.vstack(l).all(axis=0)
def or_stack(*l):
return numpy.vstack(l).any(axis=0)
k = 10 # number of arrays to be combined
perfplot.plot(
setup=lambda n: [numpy.random.choice(a=[False, True], size=n) for j in range(k)],
kernels=[
lambda l: and_recursive(*l),
lambda l: and_reduce(*l),
lambda l: and_stack(*l),
lambda l: or_recursive(*l),
lambda l: or_reduce(*l),
lambda l: or_stack(*l),
],
labels = ['and_recursive', 'and_reduce', 'and_stack', 'or_recursive', 'or_reduce', 'or_stack'],
n_range=[2 ** j for j in range(20)],
logx=True,
logy=True,
xlabel="len(a)",
equality_check=None
)
Here below the performances for k = 4.
And here below the performances for k = 10.
It seems that there is an approximately constant time overhead also for higher n.

- 1,219
- 1
- 17
- 20
-
1Try adding `functools.reduce(numpy.logical_and, l)` and `functools.reduce(numpy.logical_or, l)` to your comparison. Interestingly enough, I found them to be actually faster than your recursive implementation for both `k=4` and `k=10`, especially if `len(a) < 10**4`. – ruancomelli Feb 05 '21 at 13:56
using the sum function:
a = np.array([True, False, True])
b = array([ False, False, True])
c = np.vstack([a,b,b])
Out[172]:
array([[ True, False, True],
[False, False, True],
[False, False, True]], dtype=bool)
np.sum(c,axis=0)>0
Out[173]: array([ True, False, True], dtype=bool)

- 41
- 1
a = np.array([True, False, True])
b = np.array([False, False, True])
c = np.array([True, True, True])
d = np.array([True, True, True])
# logical or
lor = (a+b+c+d).astype(bool)
# logical and
land = (a*b*c*d).astype(bool)

- 189
- 2
- 14
If you want a short (maybe not optimal) function for performing logical AND on multidimensional boolean masks, you may use this recursive lambda function:
masks_and = lambda *masks : masks[0] if len(masks) == 1 else masks_and(np.logical_and(masks[0], masks[-1]), *masks[1:-1])
result = masks_and(mask1, mask2, ...)
You can also generalize the lambda function for applying any operator (function of 2 arguments) with distributive property (such as multiplication/AND, sum/OR and so on), assuming the order is also important, to any objects like this:
fn2args_reduce = lambda fn2args, *args : args[0] if len(args) == 1 else fn2args_reduce(fn2args, fn2args(args[0], args[1]), *args[2:])
result = fn2args_reduce(np.dot, matrix1, matrix2, ... matrixN)
which gives you the same result as if you use @
numpy operator):
np.dot(...(np.dot(np.dot(matrix1, matrix2), matrix3)...), matrixN)
For example fn2args_reduce(lambda a,b: a+b, 1,2,3,4,5)
gives you 15 - sum of these numbers (of course you have a much more efficient sum
function for this, but I like it).
Even more generalized model for functions of N arguments could look like this:
fnNargs_reduce = lambda fnNargs, N, *args : args[0] if len(args) == 1 else fnNargs_reduce(fnNargs, N, fnNargs(*args[:N]), *args[N:])
fnNargs = lambda x1, x2, x3=neutral, ..., xN=neutral: x1 (?) x2 (?) ... (?) xN
Where neutral means it is neutral element for (?) operator, eg. 0 for +, 1 for * etc.
Why? Just for fun :-)

- 455
- 1
- 7
- 20