Trollsors
Trollsors

Reputation: 492

False should not be treated as 0

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

Answers (5)

hootnot
hootnot

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

tobias_k
tobias_k

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:

  • As you modify the loop while iterating it, you could miss elements, as you remove the ith element, then advance to the i+1th, but the former i+1th element is now the ith, so you skip that. This problem is kind of countered by the second problem, though.
  • When you do 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

Rory Daulton
Rory Daulton

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

Jay
Jay

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

Abhilash Dindalkop
Abhilash Dindalkop

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

Related Questions