When to use range(len()) in a loop? Carly's Clippers Project

Carly’s Clippers Project

I’m having a tough time understanding loops. Specifically when to/not to use range(len()) when creating a loop.

I am working on the Carly’s Clippers project for example.

Carly thinks she can bring in more customers by advertising all of the haircuts she has that are under 30 dollars.
Use a list comprehension to create a list called cuts_under_30 that has the entry hairstyles[i] for each i for which new_prices[i] is less than 30 .
You can use range() in your list comprehension to make i go from 0 to len(new_prices) - 1 .

Here is my code that throws an index out of range error. Ignore the project instructions to use list comprehension. I’m struggling enough already.

hairstyles = ["bouffant", "pixie", "dreadlocks", "crew", "bowl", "bob", "mohawk", "flattop"]

new_prices = [25, 20, 35, 15, 15, 30, 45, 30]

cuts_under_30 = []

for item in new_prices:
  if new_prices[item] < 30: 
    cuts_under_30.append(hairstyles[item])

print(cuts_under_30)

However, if I change one of the lines to for item in range(len(new_prices)):, the code works. Why do I need to use range(len())? Why am I getting index out of range?

In other loops I don’t use range(len()) but don’t get an index error:

prices = [30, 25, 40, 20, 20, 35, 50, 35]

total_price = 0

for price in prices:
  if price > 0:
    total_price += price
1 Like

Hey there @drakenewkirk05968273!! Welcome to the Codecademy forums!! :grinning:

Well currently you are recieving the index out of range error bcause of the way your for loop and you list indexing is written:

for item in new_prices:
  if new_prices[item] < 30:

Try printing out what item is equal to:

for item in new_prices:
  print(item)
2 Likes

Thanks for the reply.

I think for item in new_prices: print(item) is starting to shed some light onto whats going on in my loop but I still don’t feel like I fully understand it.

Using for item in new_prices: print(item) outputs 25 from my new_prices list. item = each element from new_prices example: [25, 20, 35, …]

When the loop gets to if new_prices[item] < 30 it plugs in the elements from new_prices. new_prices[25] and tries to resolve the 25th, 20th, 35th, index of the list new_prices which doesn’t exist because new_prices only has 8 elements. Thats where I’m getting Index out of Range.

Using range(len(new_prices)) creates a list [0, 1, 2, .., 7]. Using this list, the loop resolves
if new_prices[0, 1, 2, ...] < 30: and can then continue on to append the hairstyle to the cuts_under_30 list.

Am I correct in my understanding? And another question which might help me understand further: Is there a way to do this without using range(len())?

1 Like

Bingo, perfect!!

Well it depends on the situation, in this current case you don’t actually need the index of the item you are appending to new_prices so you could ignore indexes all together, and just refer to the item itself.
For example:

lst = [10, 20, 30, 40, 50, 60]
new_lst = []

for item in lst:
  if item > 30:
    new_lst.append(item)

print(new_lst)  #prints [40, 50, 60]

However in the event you need the index of these items, you no longer have it.

1 Like

Well I still don’t fully understand why we need to use range(len()) and not just the list name. I am guessing it relates to the indexing of the element but not sure.
here is how i was trying to complete the last exercise in Carly’s Clipper Project:

hairstyles = ["bouffant", "pixie", "dreadlocks", "crew", "bowl", "bob", "mohawk", "flattop"]
new_prices = [25, 20, 35, 15, 15, 30, 45, 30]

cuts_under_30 = [hairstyles[i] for i in hairstyles if new_prices[i] < 30]

print(cuts_under_30)

which led to a TypeError: list indices must be integers or slices, not str
of course that changing the list name to range(len(hairstyles)) it worked fine.
I know the format of List comprehensions is:
new_list = [ operation for item in list] so why we use range(len()) here?

Yes, by index would be correct. Can you see why the index is used instead? Whilst a lot of Python for loops/comprehensions follow the layout you provided occasionally it’s necessary to work by index instead. Using range(len) would provide you with a series of values e.g.

print(list(range(5)))  # wrapped in list here since we want the sequence.
Out> [0, 1, 2, 3, 4]

Since they start at zero and stop before len we effectively have the indices for a sequence that is five elements long. So what happens if we have two lists related to one another by index that we want to use together?

my_cats = ['Pierre', 'Carlotta', 'Astrophe', 'Big Tom', 'Small Tom']
cat_description = ['Opulent', 'Suave', 'Disaster', 'Small', 'Not small']
print(f'{my_cats[0]} is known for being {cat_description[0]}')
Out> Pierre is known for being Opulent
print(f'{my_cats[3]} is known for being {cat_description[3]}')
Out> Big Tom is known for being Small.

So we have two lists where we keep having to write out the same index. How would we achieve this is in a loop? Indexing would be the route many would choose.

*For this specific example on cats zip would probably be a better shout. Would you stick it in your comprehension though? Your call.

1 Like

Thanks for your prompt and clear respond.
so if i understand, when we want to connect lists by their index location i should use range(len()) to be the connector. So as for your cat lists example this should be the format as well:

my_cats = ['Pierre', 'Carlotta', 'Astrophe', 'Big Tom', 'Small Tom']
cat_description = ['Opulent', 'Suave', 'Disaster', 'Small', 'Not small']
funny_cats = [my_cats[i] +" is known for being "+ cat_description[i] for i in range(len(my_cats))]
print(funny_cats)
2 Likes

Aye pretty much, range is a nice one option since it does all the heavy lifting for you but you could use a different iterable or sequence if it suited.