FAQ: Code Challenge: Loops - Odd Indices

Does the said solution employ a range object? If so, think of that object as a sort of mask that exposes some elements, but not others.

Let’s visualize…

[7, 4, 3, 5, 9, 2, 6, 1, 8]

The disorder of the above is preserved in the list, which is ordered. The elements in the list all have an index. Being as they are integers, half will be odd and half will be even, give or take.

 -     -     -     -     -    =>  even indices
[7, 4, 3, 5, 9, 2, 6, 1, 8]
    .     .     .     .       =>  odd indices

Using range to build a template from the above information permits us to grab only the ones we want.

range(0, len(...), 2)    =>  evens
range(1, len(...), 2)    =>  odds

You’d want to consider the input used at the time of the crash, not the one where you got a successful result. The error message you’re getting is saying something about what the problem is, how could that possibly happen for your code, what would necessarily have to happen to cause that? What would be required for that code to not define that variable, what would cause that part of the code to not run at all?

Also, seems like you’re making a whole lot of copies of parts of the list, probably not so great of a strategy.

As for neat strategies, how about:

chunk it into groups of 2
drop 1 from each chunk
concat

1 Like

Thanks for the explanation. The solution provides an empty list before running the range, so then adds the selected items provided to that empty list and then returns that new list (instead of substracting the amount of elements equal to the lenght of the original list as I did. It goes like this:

def odd_indices(lst):
  new_lst = []
  for index in range(1, len(lst), 2):
    new_lst.append(lst[index])
  return new_lst

Anyway, and this might be me still grasping too little, I don’t understand why providing the new_lst before the for loop in this case does not bring any error.

Even if you don’t have the time to answer this further quiestion, thanks a lot for the previous thorough explanation!

1 Like

We need to define the object before we start assigning to it, and once inside the loop we want the object to be persistent, as in keeping its values as they accumulate. It would make little sense to define the object inside the loop. We’d end up with length one.

Thank you! I.m facing a similar situation with another exercise.

1 Like

Hi, need help with the code I wrote for this particular exercise

#Write your function here
def odd_indices(lst):
  empty_list = []
  for i in lst:
    while (not i < 0) and i%2 != 0 and i <= (len(lst)-1):
      empty_list.append(lst[i])
      i += 2
  return empty_list

#Uncomment the line below when your function is done
print(odd_indices([4, 3, 7, 10, 11, -2]))

This returns me with [10, -2]

In that loop, i is a value, not an index.

How should I correct my code in order for it to work as the way I intended to?

We will for sure need the indices. range() comes to mind.

Hi, I’m trying to use list comprehension to solve this problem and I’m very confused as to why I keep getting a generic SyntaxError (invalid syntax) on my list comprehension line.

I’ve used the placeholder “{List Comprehension}” to stand in for all four of my attempts (reproduced below); all produce the same error. Can someone please tell me what I’m doing wrong?

def odd_indices(lst):
---new = []
---{List Comprehension}
---return new

#List comprehension attempt 1: new = new.append(lst[i]) for i in range(1,len(lst),2)

#List comprehension attempt 2: new.append(lst[i]) for i in range(1,len(lst),2)

#List comprehension attempt 3: new = new.append(lst[i]) for i in lst[i] if i % 2 != 0

#List comprehension attempt 4: new.append(lst[i]) for i in lst[i] if i % 2 != 0

Let’s look at the elephant in the room… list.append(). It cannot be used in a comprehension because it is an action, not an expression. The construct is the list we wrap it in, and all values generated from the for loop/conditional are written into the list as they occur.

That’s the list object where we write the comprehension, literally.

new = [lst[i] for i in range(len(lst)) if i % 2 == 1]

We can remove the conditional by applying your range.

new = [lst[i] for i in range(1, len(lst), 2)]

Bottom line, the expression left of the for is the value that ends up in the new list; operative word being, 'expression'.

Okay, I think I understand now. Thank you!

1 Like

Awesome!

Addendum

Another form of comprehension is a spread.

>>> [*range(1, 30, 2)]
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29]
>>> 

The * is known as the spread operator. It activates the iteration of the range, but we need to enclose it in a list, tuple, or set. This is handy when we want to test a range before we adopt it. Also useful if we wish to represent it.

I wanted to run this without using the range(starte,end,step). So I tried to criate a variable indexn that would start at index 1 and in each loop would increase by two so that only the elements of odd indexes would be included in the new list. However it seems that somehow the while loop does not use indexing correctly or I messed up one of the conditions. Happy to read your thoughts:

def odd_indices(lst):
  oddlist = []
  indexn = 1
  while indexn <= len(lst):
    oddlist.append(lst[indexn])
    indexn +=indexn+2
  return oddlist
    
print(odd_indices([4, 3]))
print(odd_indices([4, 3, 0]))
print(odd_indices([4, 3, 0, 4]))

Gives the following out of rage error statement:

Traceback (most recent call last):
  File "script.py", line 14, in <module>
    print(odd_indices([4, 3, 0, 4]))
  File "script.py", line 6, in odd_indices
    oddlist.append(lst[indexn])
IndexError: list index out of range

The line indexn += indexn + 2 will rapidly become oversized. Remember how += is different to = . The following lines will provide the same value.

x += 2
x = x + 2

If this line was changed what index would you be trying to access in the second iteration of a loop through [4, 3, 0]?
Double check the logic behind your loops.

Give that line some thought. See anything out of place?

Hi all,

I had a question about this assignment “odd indices” assignment. I’m getting a “list index out of range” error in my initial test but both my IDLE and Sublime run the code as expected (although I’m sure I can get it running through alternative methods). I’m just checking if anyone has insight as to why this happens. Thanks!! (I’ve attached images below)

def odd_indices(lst):
	odd_list = []
	counter = 0
	odd = 1
	for i in lst:
		odd_list += [lst[odd]]
		counter = counter + 1
		odd = odd + 2
		if counter == len(lst)/2:
			break
	return odd_list

Screen Shot 2020-05-07 at 5.19.23 PM

Your method raises that error when it is given a list with odd length.

>>> odd_indices([4, 3, 7, 10, 11, -2, 9])
Traceback (most recent call last):
  File "<pyshell#39>", line 1, in <module>
    odd_indices([4, 3, 7, 10, 11, -2, 9])
  File "<pyshell#38>", line 6, in odd_indices
    odd_list += [lst[odd]]
IndexError: list index out of range
>>> odd_indices([4, 3, 7, 10, 11, -2])
[3, 10, -2]
>>> 
2 Likes

Ah so… how silly of me, all my tests were with even length lists. Thanks for pointing that out!

1 Like

3 posts were split to a new topic: Very inefficient version, but it passed