I am trying to convert a list of lists into a single list with '1's if any of the elements in a single list is 1 and 0 otherwise. I have the following list:
result =[[-1, -1, 0], [1, 0, -1], [1, 1, 0]]
and if I use any() on the first list
i.e. result[0], I get True even though it is supposed to be false. any(result[0]) gives True.
However, when I test each element separately, I get False in each case
i.e. result[0][0] == True gives False and similar result for the remaining elements. I can't seem to understand what I'm doing wrong.
any tests if any value is truthy, not if any value equals True. All non-zero integers are truthy so any([-1, -1, 0]) is True.
See for details Truth Value Testing which applies to any and all as well.
First, why your attempts didn't work:
bool(X) = True if x != 0; else False.
Then any(result[0]) will return True, as there is at least one non-zero element in the list.
Your second test result[0][0] == True cannot work, as result[0][0] = -1, then not True (Not even boolean in fact). So it returns False.
To do what you want, you can use any with list comprehension:
result = [1 if any(y == 1 for y in x) else 0 for x in result]
>>> [0, 1, 1] For your example
EDIT:
According to Kelly Bundy's comment, another way to do it:
result = [1 if 1 in x else 0 for x in result]
You can also use boolean, but you only can reach True/False (or 1/0)
Related
I wrote a function to remove all zeroes from a list of elements with different datatypes. But while removing the zeroes. The boolean value 'False' is also removed. But when I change it to 'True' it is not removed. I tried many different methods for doing this, but the result is the same.
def move_zeros(array):
for i in range(array.count(0)):
array.remove(0)
print(array)
move_zeros([0,1,None,2,False,1,0])
The output is
[1, None, 2, 1]
How can I do this without getting the 'False' value removed ?
False and True are equal to 0 and 1 respectively. If you want to remove 0 from a list without removing False, you could do this:
my_list = [0,1,None,2,False,1,0]
my_list_without_zero = [x for x in my_list if x!=0 or x is False]
Since False is a single object, you can use is to check if a value is that specific object.
You could try this code:
def move_zeros(array):
for i in array:
if (type(i) is int or type(i) is float) and i == 0:
addr = array.index(i)
del(array[addr])
return array
This loops over all the items on the array, then checks if it is an integer or float and if it equals 0, then deletes it if it does. The reason False was getting removed is because False, when stored on the program, evaluates to 0.
You can try this:
def move_zeros(array):
array = [x for x in array if x is False or x!=0]
print(array)
move_zeros([0,1,None,2,False,1,0])
Or you can try this:
def move_zeros(array):
newarray = []
for x in array:
if x is False or x!=0:
newarray.append(x)
print(newarray)
move_zeros([0,1,None,2,False,1,0])
after running any of this you should get [1, None, 2, False, 1]
This is the task:
Write an algorithm that takes an array and moves all of the zeros to the end, preserving the order of the other elements
What is wrong with this code? Why is it not keeping boolean values while iterating through the list and removing zeros? Is it because False is equal to 0?
move_zeros([False,1,2,0,1,0,1,0,3,0,1])
def move_zeros(array):
count=0
for num in array:
if num == 0:
count +=1
array.remove(0)
return array +[0]*count
Yes, False == 0 will evaluate to True in Python which is why False values are being removed from your array.
In Python, True and False are implemented as singletons, meaning all False values point to the same instance. Therefore, you can use the is operator to check if a value is exactly equal to this singleton.
False is 0 will return False, while False == 0 will return True.
x = len(lis)
y = []
for i in range(len(lis)):
if lis[i]!=0:
y.append(lis[i])
if len(y)!=len(lis):
z = len(lis)-len(y)
for i in range(z):
y.append(0)
Seems like its a homework problem. Happy to help tho.
Edit: use print(y) and you'll get what you want
Yes, indeed False == 0. Actually, bool is a subtype of int. If you want to strictly compare if False is equal to 0, then another comparison should be added to the if statement.
Also, do not modify a list while you are iterating over itself. Create a new one instead.
def move_zeros(list_):
result = []
zeros = 0
for item in list_:
if item == 0 and type(item) == int:
zeros += 1
continue
result.append(item)
return result + [0] * zeros
Yes 0 evaluates to False and 1 evaluates to True, use this
def move_zeros(obj):
new_list = []
zeros_list = []
for item in obj:
if item != 0 or is False:
new_list.append(item)
else:
zeros_list.append(item)
new_list.extend(zero_list)
return new_list
This adds all non 0 to one list and all 0's to another, then returns the new_list after iterating over the zeros_list and adding them to the end of the new_list
There are 2 issues in your code:
You directly changed the list over which you iterate — it is always dangerous.
Other answers explained to you why False == 0 is True.
I made as few changes in your code as it was possible to fix these issues:
I created a new, empty array, and instead of removing “bad” elements from the original list, I appended the “good” ones to that new array.
I tested a current element for its type, too.
def move_zeros(array):
count=0
new_array = []
for num in array:
if num == 0 and type(num) is int:
count +=1
else:
new_array.append(num)
return new_array + [0]*count
Test:
move_zeros([False,1,2,0,1,0,1,0,3,0,1])
[False, 1, 2, 1, 1, 3, 1, 0, 0, 0, 0]
Looking to understand the meaning of bool on a generator expression in python.
bool(x for x in []) yields True
bool(x for x in [1, 2, 3]) yields True
bool(range(0)) yields False (??)
bool(range(3)) yields True
The confusion arises from range not returning a generator.
In general generators are just objects and therefore are always truthy (as opposed to containers which are False when empty).
If you do type(range(0)) you get "range", but it's not a generator, and apparently has an implicit truth value when it is empty vs non empty.
bool returns true for 'truthy' values and false for 'falsy' values.
Case 1:
(x for x in [])
Creates a generator object.
Ouput:
<generator object <genexpr> at 0x03DCDEF0>
Since an object is generated, its Truthy and it returns True.
Case 2:
(x for x in [1, 2, 3])
Same as above
Case 3:
(range(0))
This is just range(0, 0).
Try this:
for i in range(0): print(i)
There will be no output.
You will not get any value, which is Falsy and False is returned.
Case 4:
(range(3))
Try this:
for i in range(3): print(i)
Ouput:
0
1
2
Values are returned which means its truthy and True is returned.
More on Truth Value Testing
I don´t understand why it returns False, if sequence[0] is bigger than sequence[1]
sequence=[10, 1, 2, 3, 4, 5]
a=any(q for q in range(len(sequence)-1) if sequence[q]>=sequence[q+1])
print(a)
It works for the indexes bigger than 0
Your problem is that, for this list, (q for q in range(len(sequence)-1) if sequence[q]>=sequence[q+1]) is (0), and 0 is falsey.
Putting the actual indices into any kind of iterable is a red herring here - and you probably don't realise you're actually doing it. What you want to do is merely check if the predicate sequence[q]>=sequence[q+1] is true for any q. So do this instead:
any(sequence[q]>=sequence[q+1] for q in range(len(sequence)-1))
This gives an iterable of booleans, and checks if any are True or not.
First remove the any() to see what your comprehension actually gives you:
[q for q in range(len(sequence)-1) if sequence[q]>=sequence[q+1]]
>>> [0]
That is, there is one pair of numbers where the condition is true, and it is at index 0 in the original list.
any([0]) is then False because 0 is false. any() checks each item to see whether it's truthy.
Robin's solution is the usual way to do it, by using the comparison result as the yielded value. But it can be quite a lot faster to not yield false values, which you might notice if your sequence is long enough, so you could use this form:
any(True for q in range(len(sequence)-1) if sequence[q]>=sequence[q+1])
I am new to Python and was playing with it until I have a problem with any() function. According to the Python library, the code for it is:
def any(iterable):
for element in iterable:
if element:
return True
return False
I created a list: list = [-1, 1] and I expected:
print any(list) < 0
print any(x < 0 for x in list)
would print two True's and the two statements are equivalent. But instead Python printed
False
True
Why is the first statement False? How is it different from the second one?
any(list) returns a boolean value, based only on the contents of list. Both -1 and 1 are true values (they are not numeric 0), so any() returns True:
>>> lst = [1, -1]
>>> any(lst)
True
Boolean values in Python are a subclass of int, where True == 1 and False == 0, so True is not smaller than 0:
>>> True < 0
False
The statement any(list) is in no way equivalent to any(x < 0 for x in list) here. That expression uses a generator expression to test each element individually against 0, and there is indeed one value smaller than 0 in that list, -1:
>>> (x < 0 for x in lst)
<generator object <genexpr> at 0x1077769d8>
>>> list(x < 0 for x in lst)
[False, True]
so any() returns True as soon as it encounters the second value in the sequence produced.
Note: You should avoid using list as a variable name as that masks the built-in type. I used lst in my answer instead, so that I could use the list() callable to illustrate what the generator expression produces.
As stated in the docs, any(list) returns a boolean. You're comparing that boolean to the integer 0:
>>> any(list)
True
>>> True < 0
False