HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Remove last odd number from number list in Python

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
lastnumberremovepythonlistfromodd

Problem

The simplified question is:


Given a list of numbers, write a Python script that will remove the last odd number from the list.

One of the challenges is if the last odd number appears multiple times, some approaches will remove the first occurrence of that number, rather than the last.

One solution that I have is to find the max index for the odd numbers and then pop that number from the list:

def remove_last_odd(numbers):
    count = 0
    for num in numbers:
        if num%2 == 1:
            max = count
        count += 1
    print max
    numbers.pop(max)

def run():
    numbers = [1, 7, 2, 34, 8, 7, 2, 5, 14, 22, 93, 48, 76, 15, 7]
    print numbers
    remove_last_odd(numbers)
    print numbers

run()


This works, but I feel like there's got to be a better way. I've thought about reversing the list, removing the first odd number and then re-reversing:

# use this instead of remove_last_odd function
def remove_backwards(numbers):
    rev_num = numbers[::-1]
    for num in rev_num:
        if num % 2 == 1:
            rev_num.remove(num)
            numbers = rev_num[::-1]
            return numbers


This also works, and feels cleaner, but if anyone can provide advice on preferred methods/more Pythonic approaches, it'd be much appreciated!

Solution

By my interpretation, if the list contains no odd numbers, then the function should make no change. Your first function, since it unconditionally ends with numbers.pop(max), will crash with an UnboundLocalError: local variable 'max' referenced before assignment.

count += 1 is awkward. Counting loops are normally written using some kind of range() or enumerate().

The first implementation is inefficient, since it examines the entire list from the beginning.

The second function, as you noted, is inefficient in that it makes two copies of the list. Furthermore, rev_num.remove(num) is fully O(n): it performs another linear search, and then it copies the rest of the elements to fill the hole.

I would write a solution this way. This function mutates the list, and also indicates which index was removed, if any.

def remove_last_odd(numbers):
    for i in range(len(numbers) - 1, -1, -1):
        if numbers[i] % 2:
            numbers.pop(i)
            return i
    return None


Here is another way to do it, using enumerate() and reversed(), which iterates backwards without copying the list. Note that it returns a negative index.

def remove_last_odd(numbers):
    for i, num in enumerate(reversed(numbers), 1):
        if num % 2:
            numbers.pop(-i)
            return -i
    return None

Code Snippets

def remove_last_odd(numbers):
    for i in range(len(numbers) - 1, -1, -1):
        if numbers[i] % 2:
            numbers.pop(i)
            return i
    return None
def remove_last_odd(numbers):
    for i, num in enumerate(reversed(numbers), 1):
        if num % 2:
            numbers.pop(-i)
            return -i
    return None

Context

StackExchange Code Review Q#120890, answer score: 7

Revisions (0)

No revisions yet.