Reputation: 492
I have to iterate over a list containing random values like
["a",0,0,"b",None,"c","d",0,1,False,0,1,0,3,[],0,1,9,0,0,{},0,0,9]
and move all zeroes(0) to the end of the list preserving the order of other elements. This is my code:
for i in range(len(array)):
if array[i] ==0 and array[i] is not False:
array.append(array[i])
array.remove(array[i])
return array
The code works fine but it treats 'False' as 0 so the output doesn't match to the desired one. I've tried searching for the answer and have implemented them to my code like using 'is' and 'is not', but they don't seem to be working for me. What else can I do?
My Output: ['a', 'b', None, 'c', 'd', 1, 1, 3, [], 1, 9, {}, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
however the output should be ['a', 'b', None, 'c', 'd', 1, False, 1, 3, [], 1, 9, {}, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Upvotes: 3
Views: 317
Reputation: 1014
L = ['a', 0, 0, 'b', None, 'c', 'd', 0, 1, False, 0, 1, 0, 3, [], 0, 1, 9, 0, 0, {}, 0, 0, 9]
def doit(l):
# since you want all 0 to the end there is only the need to count them
n = 0
for i in l:
if i == 0 and i is not False:
n += 1
else:
yield i
# or yield [0] * n, but that yields an array of [0, 0, ...]
for _ in [0] * n:
yield _
na = [x for x in doit(L)]
print(L)
print(na)
Output:
['a', 0, 0, 'b', None, 'c', 'd', 0, 1, False, 0, 1, 0, 3, [], 0, 1, 9, 0, 0, {}, 0, 0, 9]
['a', 'b', None, 'c', 'd', 1, False, 1, 3, [], 1, 9, {}, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Upvotes: 0
Reputation: 82929
There are two problems with your code, and neither of those has anything to do with how you compare with 0
in your if
check. Indeed, both array[i] == 0 and array[i] is not False
and the shorter array[i] is 0
would work, although the latter should be handled with care; it works in your case, and with the current version of Python, but will not work for larger numbers and might not work with 0 in other versions (see here for the details).
The actual problems are:
i
th element, then advance to the i+1
th, but the former i+1
th element is now the i
th, so you skip that. This problem is kind of countered by the second problem, though.array.remove(array[i])
, you remove the first element from the array that is equal to array[i]
, i.e. equal to 0
. This includes False
, so when you hit the first 0
after the False
, you remove the False
instead, and when you hit the next 0
, you remove the 0
before that, and so on.As already noted in other answers, the best way to fix this would be to create a new array, either with an explicit loop or with a list comprehension or filter
.
Upvotes: 0
Reputation: 22564
There are many ways to move the zeros to the end of the array. Here is one way that iterates over the list (as required) and avoids any advanced Python features. Note that this uses a temporary array, since it is a very bad idea to reorder the items in a list while you are iterating over it.
array = ["a",0,0,"b",None,"c","d",0,1,False,0,1,0,3,[],0,1,9,0,0,{},0,0,9]
newarray = []
for item in array:
if item != 0 or item is False:
newarray.append(item)
while len(newarray) < len(array):
newarray.append(0)
array = newarray
print(array)
This gives the printout
['a', 'b', None, 'c', 'd', 1, False, 1, 3, [], 1, 9, {}, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
If you want to understand why Python treats False
as equal to 0
, you should understand that False
and True
are members of the bool
type, which is a sub-type of int
. In other words, False
really is 0
but with a special type. That is usually a great idea, but you found one case where it makes things more complicated.
Upvotes: 5
Reputation: 24905
Solution using filter
Please see the solution below, it tries to segregate the non-zero and zero elements while taking care of the False requirement.
data_list = ["a",0,0,"b",None,"c","d",0,1,False,0,1,0,3,[],0,1,9,0,0,{},0,0,9]
print("Input List = %s" %(data_list))
nz_list = filter(lambda x : (x != 0 or (x == 0 and x is False)), data_list)
z_list = filter(lambda x : (x == 0 and x is not False), data_list)
print("Non Zero Elements List with Order = %s" %(nz_list))
print("Zero Elements List = %s" %(z_list))
res_list = nz_list + z_list
print("Result List = %s" %(res_list))
Output:
Input List = ['a', 0, 0, 'b', None, 'c', 'd', 0, 1, False, 0, 1, 0, 3, [], 0, 1, 9, 0, 0, {}, 0, 0, 9]
Non Zero Elements List with Order = ['a', 'b', None, 'c', 'd', 1, False, 1, 3, [], 1, 9, {}, 9]
Zero Elements List = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Result List = ['a', 'b', None, 'c', 'd', 1, False, 1, 3, [], 1, 9, {}, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Upvotes: 2
Reputation: 1
array = ["a",0,0,"b",None,"c","d",0,1,False,0,1,0,3,[],0,1,9,0,0,{},0,0,9]
for i in range(len(array)):
if type(array[i]) is bool:
if array[i] is False:
array[i] = 'False'
else:
array[i] = 'True'
elif array[i] is 0:
array.append(array[i])
array.remove(array[i])
print(array)
This may not be the exact solution. However it may help you to detect the boolean and show it as 'False' or 'True' in terms of string in the list.
Upvotes: 0