6

I'm trying to move all zeros in a list to the back of the line, my only problem is there is a False bool in the list. I just found out that False == 0, so how do i move all zeros to the back of the list and keep false intact?

def move_zeros(array):
    #your code here
    for i in array:
        if i == 0:
            array.remove(i)
            array.append(i)
    answer = array
    print answer

move_zeros(["a",0,0,"b",None,"c","d",0,1,False,0,1,0,3,[],0,1,9,0,0,{},0,0,9])

This is what it returns when you run it.

['a', 'b', None, 'c', 'd', 1, 1, 3, [], 1, 9, {}, 9, 0, 0, 0, 0, 0, False, 0, 0, False, 0, 0]
be_good_do_good
  • 4,311
  • 3
  • 28
  • 42
Dane Barnett
  • 61
  • 1
  • 3

9 Answers9

7

What you're doing is basically a custom sort. So just implement it this way:

array.sort(key=lambda item: item == 0 and not isinstance(item, bool))

What this means is "Transform the array into a boolean one where items which are 0 are True and everything else is False." Then, sorting those booleans puts all the False values at the left (because they are like 0), and the True values at the right (like 1).


Originally I had written a solution which is not supported in Python 3:

array.sort(lambda L,R: -1 if R is 0 else 0)

What this means is "L is less than R if R is 0". Then we sort according to that. So we end up with any zeros on the right, because anything is less than them. The above only works in Python 2, however.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • This is by far the most elegant solution. – gglasses Sep 05 '16 at 13:21
  • This raises a `TypeError` with python3 – Chris_Rands Sep 05 '16 at 14:37
  • @Chris_Rands: Wow, I didn't realize but Python 3 entirely removed the `cmp` parameter to `sort()` and `sorted()`. I'll update my answer to include Python 3 compatible code. – John Zwinck Sep 06 '16 at 01:16
  • 1
    I don't think it is guaranteed that all values 0 are the same object. – RemcoGerlich Sep 06 '16 at 11:37
  • 1
    I would avoid using the `is` operator to compare two integers. In this case you are relying on an implementation detail in cpython, which keeps the integers in the range [-5, 256] in cache. This is not guarateed to be the case in other runtimes. http://stackoverflow.com/questions/15171695/weird-integer-cache-inside-python – Håken Lid Sep 12 '16 at 10:10
  • –1 never rely on implementation detail (fragile and subject to change without warning) – wim Jan 06 '20 at 19:40
  • @wim: Thanks for your feedback, I've edited the answer to use `isinstance` instead of `is`, which should make the code portable to "other" Python implementations. – John Zwinck Jan 19 '20 at 10:42
  • I don't uderstand your item function – Nassim El Hormi Dec 04 '20 at 23:22
3

You can use sorted:

sorted(array, key=lambda x: x is 0)
Ernest
  • 2,799
  • 12
  • 28
2

Here is one way. Note, False == 0 is True but False is 0 is False.

>>> l = ["a",0,0,"b",None,"c","d",0,1,False,0,1,0,3,[],0,1,9,0,0,{},0,0,9]
>>> [x for x in l if x is not 0] + [x for x in l if x is 0]
['a', 'b', None, 'c', 'd', 1, False, 1, 3, [], 1, 9, {}, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

EDIT: This is worse than the sorted solutions, both less elegant and requires iterating over the list twice.

Chris_Rands
  • 38,994
  • 14
  • 83
  • 119
1

Because list sorting is stable you can do

array.sort(key=(lambda x: 1 if (x==0 and x is not False) else 0))

comparing identity on numbers (x is 0) is dangerous because while it normally works, there is no guarantee.

Using key makes sorting much faster.

Actually you could also do

sorted_array=[]
zeroes=0
for e in array:
    if e==0 and e is not False:
        zeroes+=1
    else:
        sorted_array.append(e)
sorted_array.extend([0]*zeroes)

which in theory should be less work but is propably much slower in practice

janbrohl
  • 2,626
  • 1
  • 17
  • 15
0
for i in array:
    if i == 0 and i is not false:
        array.remove(i)
        array.append(i)
answer = array
print answer
jbsu32
  • 1,036
  • 1
  • 11
  • 31
0

if i == 0 and type(i) is int :

You can do it in above way. Whole program looks as below:

def move_zeros(array):
    #your code here
    for i in array:
        if i == 0 and type(i) is int:
            array.remove(i)
            array.append(i)
    answer = array
    print answer
be_good_do_good
  • 4,311
  • 3
  • 28
  • 42
0

I read from this post that Python treats 0 as boolean False. So it will always be placed on the end of your arrays like the 0s. I suggest casting boolean False as type String first, 'False', so it will not be affected by your sort.

my_list=["a",0,0,"b",None,"c","d",0,1,'False',0,1,0,3,[],0,1,9,0,0,{},0,0,9]

When you need to use it as boolean just cast it as bool:

false = False
print type(false) //output is <type 'bool'>
Community
  • 1
  • 1
Adi Mabfalin
  • 316
  • 2
  • 3
  • 12
0

The following is an O(n) linear scan algorithm, as opposed to the O(nlogn) and O(nn) algorithms given already. Move non-0 items just once and add 0s in one batch.

def move_zeros(array):
    "Mutate list by putting int 0 items at the end, in O(n) time."
    dest = 0
    zeros = 0
    for item in array:
        if not item and type(item) is int:  # int 0
            zeros += 1
        else:
            if zeros:
                array[dest] = item
            dest += 1
    array[-zeros:] = [0] * zeros

inn = ["a",0,0,"b",None,"c","d",0,1,False,0,1,0,3,[],0,1,9,0,0,{},0,0,9]
move_zeros(inn)
print(inn)
# ['a', 'b', None, 'c', 'd', 1, False, 1, 3, [], 1, 9, {}, 9,
#  0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Terry Jan Reedy
  • 18,414
  • 3
  • 40
  • 52
0

I know this question already has a bunch of answers but for future readers, I am just going to add my two cents to it. Most of the answers haven't covered the case of a float 0.0 which is also a zero. I am going to use the idea of the above answers in my own code.

Note: My solution may not be as elegant as the other experts.

def move_zeros(array):
# your code here
if len(array) < 1:
    return array
else:
    list = []
    zeros = 0

    for i in array:
        if not i and type(i) is int or type(i) is float:
            zeros += 1
        else:
            list.append(i)

for i in range(0, zeros):
    list.append(0)

return list

It has been tried with 25 different test cases.

Saad
  • 399
  • 8
  • 25