2

One of the revision questions involves modifying the original list by removing all integers in a list that are both odd and a multiple of x.

def remove_odd_multiples(numbers_list, multiple_of):
    for ele in numbers_list:
        if (ele%2) != 0 and (ele % multiple_of) == 0:
            numbers_list.remove(ele)
    
    return numbers_list

Output:

numbers_list = [1, 5, 23, 3, 6, 17, 9, 18]
print("Before:", numbers_list)
remove_odd_multiples(numbers_list, 3)
print("After:", numbers_list)

Before: [1, 5, 23, 3, 6, 17, 9, 18]
After: [1, 5, 23, 6, 17, 18]

It does work, however inputting the code into coderunner, my code failed a few hidden checks which are not shown. Am I going about solving this problem wrong? Should I be using pop instead of .remove?

greg-449
  • 109,219
  • 232
  • 102
  • 145
  • Please don't vandalize your own posts. When you post here, you give SO the right to distribute the content under CC-by SA 4.0. Any vandalism will be reverted. – greg-449 May 11 '21 at 14:07

2 Answers2

2

Instead of removing while iterating, you could use a list comprehension to return a new list with the result.

def remove_odd_multiples(numbers_list, multiple_of):
    return [x for x in numbers_list if x % 2 == 0 or x % multiple_of != 0]

To modify the list in-place:

def remove_odd_multiples(numbers_list, multiple_of):
    numbers_list[:] = [x for x in numbers_list if x % 2 == 0 or x % multiple_of != 0]

Looping backwards while deleting elements also ensures that unprocessed elements are not shifted.

def remove_odd_multiples(numbers_list, multiple_of):
    for i in range(len(numbers_list) - 1, -1, -1):
        if (numbers_list[i]%2) != 0 and (numbers_list[i] % multiple_of) == 0:
            del numbers_list[i]
Unmitigated
  • 76,500
  • 11
  • 62
  • 80
  • OP asked for and condition, also for changing the list passed as parameter. – Niloct May 06 '21 at 02:09
  • @Niloct The `and` condition would be for removing, not keeping. The second part of my answer addresses modifying the parameter. – Unmitigated May 06 '21 at 02:09
  • Might be worth short circuiting this method if `multiple_of` itself is even! – flakes May 06 '21 at 02:10
  • Hello, I understood the list comprehension but what does [:] do? –  May 06 '21 at 02:12
  • @didleyr6s It is used for slice assignment here, which overwrites the entire list. – Unmitigated May 06 '21 at 02:14
  • @python_user why would you be so sure of that? Slice assignment is even a part of the basic language introduction https://docs.python.org/3/tutorial/introduction.html#lists – flakes May 06 '21 at 02:18
1

I think the problem is that while iterating the list, you are also modifying it (by deleting the elements of the list).

So, try this:

def remove_odd_multiples(numbers_list, multiple_of):
    for ele in numbers_list[:]:
        if (ele%2) != 0 and (ele % multiple_of) == 0:
            numbers_list.remove(ele)
    
    return numbers_list

For more information - Strange result when removing item from a list while iterating over it

sri
  • 359
  • 2
  • 5