-2

I use the all command in Python to execute something if all entries satisfy a constraint. For example, here I check if all entries are positive and print the no. of negative numbers if all are positive. So ideally you would expect to print output of 3 if all numbers are positive and none if one of the numbers is negative. However I get the value 2 as output. Why's it so?

 if all(x>0 for x in array([-10,1,2])):
     print sum(x>0 for x in array([-10,1,2]))

enter image description here

Bravo
  • 657
  • 1
  • 8
  • 19
  • 5
    What does `array()` do? – kylieCatt May 13 '15 at 13:23
  • 1
    On my machine, your code doesn't print anything. So IMHO this works as intended... – Matt May 13 '15 at 13:23
  • Same here once I removed the call to `array()`. It's possible whatever that function is returning is satisfying the conditions for the statement to evaluate to `True`. – kylieCatt May 13 '15 at 13:24
  • 3
    *"print the no. of negative numbers if all are positive"*? Wat. – Stefan Pochmann May 13 '15 at 13:26
  • @Matt: Sorry, a typo. I expect a 3 or nothing for this code, but I get a 2. – Bravo May 13 '15 at 13:33
  • @StefanPochmann: Typo, please check now. – Bravo May 13 '15 at 13:34
  • Um, you didn't change that. And you really should answer the question of @IanAuld – Stefan Pochmann May 13 '15 at 13:39
  • 1
    I suppose he did `from numpy import *` or `from scipy import *` so probably `array` will produce a numpy array... – swenzel May 13 '15 at 13:42
  • With or without numpy/scipy, `-10` means that the `all(x>0 ...)` statement is false, and therefore won't print anything. – Matthew May 13 '15 at 13:43
  • "*if all entries are positive and print the no. of negative numbers if all are positive*"... You'll have 0 negative numbers if all are positive (depending on whether you count 0 itself as positive, I suppose). Assuming this was a typo, the number of positive numbers will be the length of the array (assuming 1d array). `sum` probably isn't the right way to go about this. Could you clarify what you're trying to do? – Bruno May 13 '15 at 14:20

4 Answers4

2

I think I got what you mean. If you enter the if statement (means that the condition was evaluated True) than it must result in 3 (because the number of positives - where x > 0 would be all of the three). Agreed.

But, in this situation, you don't even enter the if statement because the condition is evaluated False as the when comprehending a list the following way:

a = [x > 0 for x in array([-10, 2, 1])]

You should get [False, True, True] which when called as an argument to all() will result in False. Therefore, you won't even print anything. Maybe you're confusing and you're printing something somewhere else.

Either way, doesn't print anything on my system - as it shouldn't.

Zach P
  • 1,731
  • 11
  • 16
  • It is surprising. I have attached the screenshot of my window. It does print 2. – Bravo May 13 '15 at 15:20
  • @Bravo It's not so surprising: `[x > 0 for x in array([-10, 2, 1])]` and `(x > 0 for x in array([-10, 2, 1]))` (or what's without parentheses within your `all(...)`) are not the same: the former is a list, the latter is a generator. – Bruno May 13 '15 at 17:06
1

To make it clearer you're using Numpy, I'll use an explicit import instead if from numpy import *:

import numpy as np
if np.all(x>0 for x in np.array([-10,1,2])):
    print np.sum(x>0 for x in np.array([-10,1,2]))

Here, x>0 for x in np.array([-10,1,2]) is a generator, and numpy.all doesn't work on generators.

In addition, you might be interested in filtering arrays, to achieve what you want, using > 0 on the array directly as follows:

>>> import numpy as np
>>> a1 = np.array([-10,1,2])
>>> a2 = np.array([1,2,3])
>>> a1 > 0
array([False,  True,  True], dtype=bool)
>>> a2 > 0
array([ True,  True,  True], dtype=bool)
>>> np.all(a1 > 0)
False
>>> np.all(a2 > 0)
True

You may be interested in this: Boolean or “mask” index arrays

You'll find more about the behaviour of numpy.all and generators in this answer.


Regarding your secondary question (why 2 instead of 3), it's because np.sum treats True as 1 and False as 0, once you've passed the test condition. It's more visible if you expand the generator as follows:

>>> import numpy as np
>>> g = (x>0 for x in array([-10,1,2]))
>>> g
<generator object <genexpr> at 0x7f0edfc3b640>
>>> l = list(g)
>>> l
[False, True, True]
>>> np.sum(l)
2
Community
  • 1
  • 1
Bruno
  • 119,590
  • 31
  • 270
  • 376
  • Thanks Bruno. This comes closest to what I want. However, if it does not work on generators, why does the statement evaluate to a TRUE and the print command executed? – Bravo May 13 '15 at 15:26
  • [This question](http://stackoverflow.com/a/14392453/372643) might give you a better explanation. That would certainly reinforce the suggestion that it's not a good idea to use `from numpy import *` (or generally `from ... import *`), so as not to make `numpy.all` collide with Python's native `all`. It just makes the code harder to read and leads to different behaviours. – Bruno May 13 '15 at 15:30
  • Excellent. Now I see the issue here. Good lesson learnt on import. Thanks a lot. – Bravo May 13 '15 at 15:35
0

The error is in array([-10,1,2]) I use range instead and work well

if all(x > 0 for x in range(-10, 1, 2)):
    print(    sum(x > 0 for x in range(-10, 1, 2)))
Fundor333
  • 49
  • 6
0

I'm assuming you have a reason for using array and not a plain list. It's used like this, however (assuming from array import array):

array('i', [-10, 1, 2])

Where 'i' indicates this is an array of signed integers.

Regardless of whether you use the above or a plain old list, you had a correct way of counting the number of positive values. all(), as mentioned in another answer will result in False when any value in the list is False, which makes your original code never enter the if block, but it's completely superfluous here. If you only want to count the number of positive values, you can just go with your second line:

sum(x > 0 for x in array('i', [-10, 1, 2]))

(With the proper use of array, of course.)

Brian Lee
  • 158
  • 4