# FAQ: Code Challenge: Loops - Delete Starting Even Numbers

The general idea is to find the first ODD number in the list, and make it the first element of the returned list.

7 Likes

16 posts were split to a new topic: Code challenge lists - improving my code

8 posts were split to a new topic: Struggles [solved]

14 posts were split to a new topic: Code challenge lists - Accounting for an all even list?

2 posts were split to a new topic: List index out of range

2 posts were merged into an existing topic: Why doesn’t iterating with `for` work while removing items from a list?

6 posts were split to a new topic: Why doesn’t slicing an empty list throw an error?

15 posts were merged into an existing topic: Why doesn’t iterating with `for` work while removing items from a list?

For anybody exploring the multitude of possible solutions for this problem, here is another one to add to the pile…

try/except with `next()`
``````>>> def delete_starting_evens(lst):
try:
return lst[lst.index(next(x for x in lst if x % 2)):]
except StopIteration:
return []

>>> a = [10,2,30,4,51,60,75]
>>> b = [10,2,30,4,52,60,76]
>>> delete_starting_evens(a)
[51, 60, 75]
>>> delete_starting_evens(b)
[]
>>>
``````

It breaks down like this,

breakdown
``````>>> try:
y = next(x for x in a if x % 2)
z = a.index(y)
print (a[z:])
except StopIteration:
print ([])

[51, 60, 75]
>>> try:
y = next(x for x in b if x % 2)
z = b.index(y)
print (b[z:])
except StopIteration:
print ([])

[]
>>>
``````

Some things above may not yet have surfaced in this course:

1. `list.index()`
2. Handling exceptions with `try...except`.
3. The `next()` function

That being the case, one may wish to cycle back to this solution when those topics come up or on review after completing the course.

1 Like

Hm. I’m not sure I agree with both using an iterator and then going back to the start to search for the index - I would rather only consume from the iterator, and anything that has been dropped can be forgotten.

If there’s a rope sticking out of a wall (an iterator), then I could pull at it until there’s a non-even value, and then either turn the rest into a list, or let whoever wants the remaining values pull out the rest of the rope when and if they want it.

Sidenote:
Almost cheating, but interesting enough, and possibly not immediately obvious even knowing it exists - itertools.dropwhile implements a more general version of this problem: `dropwhile(even, lst)`

1 Like

itertools.dropwhile

Interesting. Thanks for that.

One could use range to expose the indices.

with `range()`
``````>>> def delete_starting_evens(lst):
try:
return lst[next(i for i in range(len(lst)) if lst[i] % 2):]
except StopIteration:
return []

>>> delete_starting_evens(a)
[51, 60, 75]
>>> delete_starting_evens(b)
[]
>>>
``````

Or, use `enumerate` to expose both index and value…

with `enumerate()`
``````>>> def delete_starting_evens(lst):
try:
return lst[next(i for i, x in enumerate(lst) if x % 2):]
except StopIteration:
return []

>>> delete_starting_evens(a)
[51, 60, 75]
>>> delete_starting_evens(b)
[]
>>>
``````

Either of which make more sense than the earlier example given your advice.

1 Like

That’s a smaller amount of loops.
If you’re going to do list slicing, I’d really like to see finding the start location as a separate step (separate line, put result in variable)
And then, if you’re going to use iterators as a strategy of finding the first value - fine.

I'm looking for something more like this for using iterators
``````def delete_starting_evens(xs):
xs = iter(xs)
for x in xs:
if x % 2 != 0:
yield x
yield from xs
return
``````
Or this, using find and slice
``````def delete_starting_evens(xs):
for i, x in enumerate(xs):
if x % 2 != 0:
return xs[i:]
return []
``````
Or after abstracting out some stuff - if the language doesn't come with the kind of words to describe what's wanted then putting it all in one function may make it a bit difficult to read. Defining the words you want allows for expressing things in nicer ways.
``````def even(n):
return n % 2 == 0

def not_(f):
def f_(*args, **kwargs):
return not f(*args, **kwargs)
return f_

def find(f, xs):
for i, x in enumerate(xs):
if f(x):
return i
return i+1

def delete_starting_evens(xs):
first_non_even = find(not_(even), xs)
return xs[first_non_even:]
``````
But obviously the right word here already exists in dropwhile, to the point where this whole function shouldn't exist at all, dropwhile covers it.
``````from itertools import dropwhile

def even(n):
return n % 2 == 0

def delete_starting_evens(xs):
return dropwhile(even, xs)
``````
3 Likes

The second example is how I originally solved this one. Love going down the rabbit hole and seeing what pops up.

Thanks again for the great examples; and, I won’t argue with your last point. It makes the most sense. You’d think I had an aversion to libraries, or something the way I never reach for them.

2 Likes

A post was merged into an existing topic: Why doesn’t iterating with `for` work while removing items from a list?

27 posts were merged into an existing topic: Why doesn’t iterating with `for` work while removing items from a list?

3 posts were split to a new topic: Infinite loop [solved]

4 posts were split to a new topic: How does break work? [solved]

8 posts were split to a new topic: Code challenge lists - improving my solution [solved]

3 posts were split to a new topic: Using continue in a while loop [solved]

7 posts were split to a new topic: How does this code loop I wrote work?