Michael Gee
Michael Gee

Reputation: 541

Unable to move 0's to the end of list properly Python

So the goal here is to move all 0's to the end of the array but I stumble across a problem from these small lines of code.

When I use the input I get the desired output like so:

Input: [0,1,0,3,12]
Output: [1,3,12,0,0]

However, whenever I use this input:

[0,0,1]

I get this output:

[0,1,0]

When I want the output:

[1,0,0]

I have no idea why I thought I implemented this properly:

class Solution:
def moveZeroes(self, nums):
    """
    :type nums: List[int]
    :rtype: void Do not return anything, modify nums in-place instead.
    """
    for counter in range(len(nums)):
        if nums[counter] == 0:
            nums.pop(counter) #Remove the 0
            nums.append(0) #Add to end. 
            counter-=1 #Check same index just incase adjacent 0

Any input is appreciated. Thanks!

Upvotes: 2

Views: 123

Answers (3)

Reut Sharabani
Reut Sharabani

Reputation: 31339

This line:

counter-=1 #Check same index just incase adjacent 0

Does not decrease the indexing for the following indices.

Try this instead:

class Solution:
    def moveZeroes(self, nums):
        """
        :type nums: List[int]
        :rtype: void Do not return anything, modify nums in-place instead.
        """
        zeros_found = 0
        for counter in range(len(nums)):
            idx = counter - zeros_found
            if nums[idx] == 0:
                nums.pop(idx) #Remove the 0
                nums.append(0) #Add to end. 
                zeros_found += 1 #Account for offset

You could also do this more functionally:

from itertools import filterfalse
# ...
def moveZeroes(self, nums):
    none_zeroes = list(filter(None, nums))
    zeros = list(filterfalse(None, nums))
    return none_zeros + zeros

Or if you don't want to create lists for no reason:

from itertools import filterfalse, chain
# ...
def moveZeroes(self, nums):
    none_zeroes = filter(None, nums)
    zeros = filterfalse(None, nums)
    return list(chain(none_zeros, zeros))

These rely on two implicit facts:

  1. bool(0) is False, and bool(x) when x != 0 is True
  2. filter(None, list) filters list by item's bool value, so no 0s (and opposite for filterfalse)

Upvotes: 3

Julien
Julien

Reputation: 15071

A for loop is not a equivalent to a while loop with increment. Your last line counter-=1 doesn't achieve anything: after you decrement counter, it immediately takes the next value in the range. (To be clear, if you were at iteration counter = 2 for example, no matter what value you leave counter at at the end of this iteration, it will be reassigned to 3 at the next iteration.)

Upvotes: 4

AKX
AKX

Reputation: 168913

I wouldn't even bother with a manual for loop...

def move_zeroes(nums):
    nums[:] = [n for n in nums if n != 0] + [0] * nums.count(0)

x = [0,1,0,3,12]
move_zeroes(x)
print(x)

outputs

[1, 3, 12, 0, 0]

Upvotes: 5

Related Questions