Code challenge lists - improving my code

hi guys, i had some trouble with this too but i think i figured it out. the instructions may be a bit misleading but essentially, our job is to remove all the even numbers in “lst” before the first odd number.

def delete_starting_evens(lst):
  while (len(lst) > 0 and lst[0] % 2 == 0):
    lst = lst[1:]
  return lst

print(delete_starting_evens([4, 8, 10, 11, 12, 15]))  #prints [11, 12, 15]
print(delete_starting_evens([2, 4, 5,  8, 10]))  #prints [5, 8, 10]

the condition for the While loop to be active is when the len(lst) is greater then 0 and lst[0] is divisible by two.

when active, the purpose of the While loop is to “reset” the parameter variable “lst” as lst[1:], which is the 1st element onwards, because the 0th element is divisible by 2 so it is left out.

this happens repeatedly until the While loop hits the first odd number in “lst”, then the function ends.

notice that the indent for “return lst” is flushed with the while loop. this means that if the given list of numbers starts with an odd number right off the bat, it will return the original lst. otherwise, this will return the remaining list inclusive of the first odd number and the rest of the numbers behind it (regardless odd or even).

please correct me if I am found to be wrong! I’m just happy to see that I’m not the only confused one around here. :slight_smile:

9 Likes

huge part of programming figuring out what exactly the requirement is. In a job you could have a client which says: I want this feature (no technically information), and you have to figure it out. Maybe not so extreme in a junior role, but in a senior role that is very realistic.

so i think the exercise is good practice to get started with understanding the problem

In your program, if the list starts with a lot of even numbers, you end up with quite a few lists.

2 Likes

Which works but does reset the list every time the first number is even. Much quicker and more efficient is to find the index of the first odd number and return the slice with that as the first element. There will be two returns, one in the loop, and one at the end.

5 Likes

If you use the first odd number as an indicator to slice the list then wouldn’t you have use some kind of an exception for lists that contain only even numbers? Otherwise all even list would never change.

The instructions are not explicit about what needs to happen a list of all even numbers. But I think it’s implied that an all even list ought to be returned empty.

1 Like

Would this be a better approach?

def delete_starting_evens(lst):      # declare the function with a single parameter.
  counter = 0                        # Find the index of each list item.
  if len(lst) > 0:                   # Does the list have more than 0 item?
    for num in lst:				     # Look at each list item.	
      if num % 2 == 1:				 # Is the list item odd? 
        lst = lst[counter:]          # Slice the list at the odd item index and forward.
        break						 # Stop the "for" loop. 
      else:                          # Else if the number is even.
        if len(lst) == counter + 1:  # If the counter and list length match (end of list).
          lst = []                   # Empty the list.
      counter += 1                   # Increment to match the next list items index.
    return lst                       # Return the list.
  else:                              # If the original list was empty at the beginning. 
    return "Please enter a list!"    # Message. 
  
  
# All possible lists should work 
print(delete_starting_evens([1, 4, 8, 10, 11, 12, 15]))   #prints  [1, 4, 8, 10, 11, 12, 15]
print(delete_starting_evens([4, 8, 10, 11, 12, 15]))      #prints  [11, 12, 15]
print(delete_starting_evens([4, 8, 10]))                  #prints  []
print(delete_starting_evens([1, 1, 1]))                   #prints  [1, 1, 1]
print(delete_starting_evens([]))                          #prints  Please enter a list!
1 Like

Odd and even are opposite states, so it follows that logic along either line will give an equal result.

Even numbers can be ignored and passed over until we reach an odd number, if one exists in the list. Using list.enumerate we access both index and value…

rainbow = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet']

for i, x in enumerate(rainbow):
    print ("{index}: {value}".format(index=i, value=x))

0: red
1: orange
2: yellow
3: green
4: blue
5: indigo
6: violet
delete starting even numbers
def delete_starting_evens(lst):
  for i, x in enumerate(lst):
    if x % 2: return lst[i:]
  return []

The key above is the return on odd only, otherwise return an empty list.

Granted, not the first thing to come to mind if the above method is unknown, but once we know about the enumerate method, we can reach for it in all kinds of circumstances. The advantage of using this method of tracking the index is that there can be duplicates in the list and all of them will have a unique index.

Using the list.index(value) method we can only actually find the first occurrence of ‘value’ in the list. In the code from the previous post counter is implemented to track the index. This approach has been covered in an earlier lesson, and is a reliable means of being on top of the correct element.

counter = 0
for value in lst:
    if value % 2: return lst[counter:]
    counter += 1
return []

Again, we return only on odd, else return an empty list. Neither of the above approaches involves reseting the list.

1 Like

Would this be a better approach?

def delete_starting_evens(lst):      # declare the function with a single parameter.
  counter = 0                        # Find the index of each list item.
  if len(lst) > 0:                   # Does the list have more than 0 item?
    for num in lst:				     # Look at each list item.	
      if num % 2 == 1:				 # Is the list item odd? 
        lst = lst[counter:]          # Slice the list at the odd item index and forward.
        break						 # Stop the "for" loop. 
      else:                          # Else if the number is even.
        if len(lst) == counter + 1:  # If the counter and list length match (end of list).
          lst = []                   # Empty the list.
      counter += 1                   # Increment to match the next list items index.
    return lst                       # Return the list.
  else:                              # If the original list was empty at the beginning. 
    return "Please enter a list!"    # Message. 
  
  
# All possible lists should work 
print(delete_starting_evens([1, 4, 8, 10, 11, 12, 15]))   #prints  [1, 4, 8, 10, 11, 12, 15]
print(delete_starting_evens([4, 8, 10, 11, 12, 15]))      #prints  [11, 12, 15]
print(delete_starting_evens([4, 8, 10]))                  #prints  []
print(delete_starting_evens([1, 1, 1]))                   #prints  [1, 1, 1]
print(delete_starting_evens([]))                          #prints  Please enter a list!
2 Likes

At this juncture in our learning path, ‘better’ and ‘best’ are hardly terms we need concern ourselves with. Writing code that works as we expect is more important so we get engrained with several approaches to, and ways to think of and describe our algorithms. it’s important to learn as much about the basics as we can absorb, then go back and reinforce it with practice and study.

No point staying on one point for too long. Keep moving forward, but review often as you go, and keep looping back to the documentation for more insight. Build on the foundation so when you do reach the larger challenges your code base is not top heavy.

4 Likes

Thanks for your time and input.

2 Likes

Removing all leading even numbers from a list containing only even numbers will result in an empty list.
There’s no need for a special case for that, not in the instructions nor in the code!
An empty input is also not a special case.

I do have bit of a reaction to your code because of how much nested control flow there’s in it. No code should look like that, it’s very difficult to read (and the very small indentation width doesn’t help either, 4 spaces is the generally accepted width to use for python). The remedy (assuming everything is required) is to turn it into sequential steps instead of nesting them within each other, or if not possible, to break out actions into functions so that each function is easily understood by itself.
Removing the not-so-special cases should tidy that up.
An example on how it could be more sequential is to find the location, then slice <- no need for nesting

1 Like

I think your answer is great.

What really confuses me is lst = lst [1:]. I though lst[1:] was to pick the last element in the list. Then lst will consist of only one last element instead of starting with an odd number. This is what confuses me the most!

1 Like

hello evelyn :slight_smile:

lst[-1] is used to pick the last element in the list
lst[1:] is used to pick the second element to the last element in the list

hopefully this helps! for this exercise, the objective of the function is:

  1. delete all the even numbers before the first odd number in the original list
  2. return a list from the first odd number to the last number in the original list

this is what the function does:

  1. use a while condition to keep deleting even numbers until we reach the first odd number
  2. each time the function deletes an even number, it also updates the ‘lst’ variable to ‘lst[1:]’ (lst[0], the first element was deleted, so the new list begins with lst[1:])
  3. the function then returns the new list with the remaining numbers, we want to achieve.
3 Likes

Thank you for your prompt response, Deniece! :blush:

1 Like

in more general terms, lst[index] will look up the value at the given index, while lst[start:stop] is list slicing, and will give you a slice of a list

2 Likes

Got it. I think I misunderstood the example given by Codecademy in the lesson (i.e. cherry, banana). I thought list [2:] would give the last two elements in a list. Thank you for your answer!

1 Like

I think you answered my question.You said said there would be 2 returns, one within the loop and one at the end. It seems that the instruction with the loop asked to make a new list of even numbers.
The def of the the function was to delete the even numbers from the original list which was given at the end of the block of code.
Am i thinking on the right track

def delete_starting_evens(lst):

# First return below is culling even numbers?

while (len(lst) > 0 and lst[0] % 2 == 0):
lst = lst[1:]
return lst##

print(delete_starting_evens([4, 8, 10, 11, 12, 15]))
print(delete_starting_evens([4, 8, 10]))