Working with Collections
In Python, we can switch the order of the terms and transcribe these to working code
as follows:
not all(isprime(x) for x in someset)
any(not isprime(x) for x in someset)
As they're equivalent, there are two reasons for preferring one over the other:
performance and clarity. The performance is nearly identical, so it boils down
to clarity. Which of these states the condition the most clearly?
The all() function can be described as an and reduction of a set of values.
The result is similar to folding the and operator between the given sequence
of values. The any() function, similarly, can be described as an or reduction.
We'll return to this kind of general-purpose reduce when we look at the reduce()
function in Chapter 10, The Functools Module.
We also need to look at the degenerate case of these functions. What if the sequence
has 0 elements? What are the values of all(()) or all([])?
If we ask, "Are all elements in an empty set prime?", then what's the answer?
As there are no elements, the question is a bit difficult to answer.
If we ask "Are all elements in an empty set prime and all elements in SomeSet
prime?", we have a hint as to how we have to proceed. We're performing an and
reduction of an empty set and an and reduction of SomeSet.
()∀∈x ∅∧Prime()x (∀∈x SomeSet)Prime()x
It turns out that the and operator can be distributed freely. We can rewrite this to a
union of the two sets, which is then evaluated for being prime:
(∀∈x ∅∪SomeSet)Prime()x
Clearly, SS∪∅≡. If we union an empty set, we get the original set. The empty set
can be called the union identify element. This parallels the way 0 is the additive
identity element: aa+= 0.
Similarly, any(()) must be the or identity element, which is False. If we think of
the multiplicative identify element, 1, where bb×= 1 , then all(()) must be True.