3

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]

Trollsors
  • 492
  • 4
  • 17
  • You should *not* be using `is` to compare with 0. But that is not the only problem here. – Daniel Roseman Feb 09 '19 at 13:17
  • I used '==' initially but I got the same problem, so I changed it to 'is' – Trollsors Feb 09 '19 at 13:20
  • Well don't change things randomly. Use `is` to compare with True and False, and `==` to compare with integers. – Daniel Roseman Feb 09 '19 at 13:23
  • For completeness, we should mention that `is` can also be used properly to compare with `None`. – Rory Daulton Feb 09 '19 at 13:40
  • @RoryDaulton Done – Trollsors Feb 09 '19 at 13:46
  • 'the output doesn't match to the desired one' . Could you post your actual output? – Jul10 Feb 09 '19 at 13:53
  • @DanielRoseman Is using `is` to compare with `0` (and _specifically_ 0) really a problem here? Shouldn't at least all small numbers really be the same object? Agree for the general case of `int`, though. – tobias_k Feb 09 '19 at 13:56
  • No, as I said that is not the only problem, there are much more serious issues with the code. But since OP is clearly a learner, it is good to get these things right from the start. – Daniel Roseman Feb 09 '19 at 13:57
  • @DanielRoseman Right, but then, in this particular case, wouldn't using `is 0` actually be a valid way to ensure that it's `0` and not `False`, provided that the "implementation detail" of small numbers being pooled holds true? Of course with a stern warning w.r.t. the general case? – tobias_k Feb 09 '19 at 14:02
  • @Jul10 right. Done. – Trollsors Feb 09 '19 at 14:04

5 Answers5

5

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.

Rory Daulton
  • 21,934
  • 6
  • 42
  • 50
2

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]
Jay
  • 24,173
  • 25
  • 93
  • 141
0
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.

0

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.

tobias_k
  • 81,265
  • 12
  • 120
  • 179
0
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]
hootnot
  • 1,005
  • 8
  • 13