Trouble with carlys clippers exercise in python course

Hey I’m doing the carlys clippers and confused with the last line that asks us to

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 .

I’m wondering about cuts_under_30 = [hairstyles[i] for i in range(len(hairstyles)) if new_prices[i] < 30] where it has to be range(len(hairstles)) when i print range(len(hairstyles it says range 0, 8 isn’t this already implied? when I try to run the code without the range len it gets TypeError: list indices must be integers or slices, not str maybe i feel there’s jsut an easy way to do it.

https://www.codecademy.com/paths/computer-science/tracks/cspath-flow-data-iteration/modules/dspath-python-loops/projects/carlys-clippers

1 Like

Hi, Miles, here’s my understanding of what you are asking:. You are using the list data type, specifically parallel lists. You are interested in something in list B that has the same position in the list (i.e., index) as another item’s position in list A. Actually, your solution does the job very well. But you do not want to use range(). Is that it??

I guess you have tried [hairstyle for hairstyle in hairstyles if something_in_price] but just what is something_in_price? You have no way of tying each hairstyle (list A) to a price (list B) without using indexing, and one way to do that is to use range(len(list)), as you have done. You could use the list.index() method, but that is pretty inefficient, as it requires a search through the list each time (obviously no big deal with a list of length 8, but …)

If you have covered the functions enumerate() or zip(), one or the other of those could also be used. (Many of these parallel list problems are better handled using the dictionary data type, but that is not what today’s lesson is about.)

3 Likes

The objective is to return a list of hairstyles that are priced below 30$. We know that both lists correspond so we can iterate over a range to get their indices…

[hairstyles[x] for x in range(len(new_prices)) if new_prices[x] < 30]

This is what is expected in the exercise. However, as @patrickd314 mentioned, there are other ways.

zip is a function for pairing up corresponding values in two separate sequences.

>>> list(zip("Python", "Python"[::-1]))
[('P', 'n'), ('y', 'o'), ('t', 'h'), ('h', 't'), ('o', 'y'), ('n', 'P')]
>>> 

Given a zipped list, we don’t need the index, just the values.

>>> [x[0] for x in zip(hairstyles, new_prices) if x[1] < 30]
['bouffant', 'pixie', 'crew', 'bowl']
>>> 

It follows that you will have learned this in a lesson at some point, or it should not be used, yet. Still, nothing to keep us from learning a little extra as we go, just so long as we first complete the exercise as expected. After passing we can go to town playing with the code and what we can learn about it.

To make it even more abuntantly clear, we can show how for can unpack each tuple in the zipped list…

>>> [a for a, b in zip(hairstyles, new_prices) if b < 30]
['bouffant', 'pixie', 'crew', 'bowl']
>>> 
5 Likes

Hello,
I’ve got the question as I’m also struggling with this part of Carly’s Clippers.
I do not understand, why do I have to use range in:

[hairstyles[x] for x in range(len(new_prices)) if new_prices[x] < 30]

I tried to use something like that:

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

because I thought it that the appropriate elements of hairstyles list would fill the new_prices list.
What’s wrong with my way of thinking?

Greetings

range will give us a sequence which we can use to poll the value at each index in the list. There are two lists, one for hairstyles, and one for prices. They both correspond so the price at index x will be for the hairstyle at index x.

We cannot use a read only loop since it will give us the value, not the index, which is what we need if we are to pair up with the other list.

1 Like

Ok, I see, thank you. :sunglasses:
But let me know if I understand this part of code corretly:

cuts_under_30=[hairstyles[x] for x in range(len(new_prices)) if new_prices[x]<30]
print(cuts_under_30)

I understand it that way:
if new_prices<30 : take its index (I mean “the place” in which the numbers are kept: for this example it would be 0,1,2,3)

and
into these places put the hairstyles
so:
‘bouffant’ --> to the place of 0
‘pixie’ --> to the place of 1
‘crew’ --> to the place of 2
‘bowl’ to the place of 3
Do I understand it properly?

1 Like

Yes, it looks like you have the idea.

x    hairstyles     prices
1    "bouffant",      30
2    "pixie",         25
3    "dreadlocks",    40
4    "crew",          20
5    "bowl",          20
6    "bob",           35
7    "mohawk",        50
8    "flattop"        35

The range produces the indices. The hairstyle at index x corresponds to the price at index x.

Hi mtf, just to confirm. The hairstyles should correspond to the “new_prices” and not “prices”, correct?

The column heading is for the customer. We control what is displayed. Not sure that helps answer your question.

Is it ok to simplified the code become like this?

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

Because the main problem is to create a new list of price under 30 based on the new price, so we can forget the hairstyles indexing.

1 Like

I really dont understand the whole codes.

I wish it will be broken down into steps and reason for each code in order for dummy to understand.

It can be difficult to process a large chunk of code at once so sometimes it’s best not to. If you want to break it down into steps then just do so.

Work through each statement one by one making sure you understand what they do and if necessary run them and print their value or similar. If you’re comfortable up until a certain point in the program flow then stop at that point and explore. If you break it down yourself you can make the steps as big or as small as you please.

1 Like

I have a feeling this has been asked - but i can’t quite piece it together
the hashed line below was my first attempt to solve the final step - i know it doesn’t work - but why doesn’t it work ? -

#cuts_under_30 = [h for h in hairstyles if h <30]

the correct answer is
cuts_30_or_less = [hairstyles[i] for i in range(len(hairstyles)) if new_price[i] <= 30]
#an explanation of what is happening here would help - i assume it’s going through every item in hairstyles and finding 30 or under - but why do we need the [i]

print(cuts_30_or_less)

(ps please explain real slow

Thanks

Because it refers to a corresponding index in a second list. We cannot do this with a read-only for loop, but must use an indexed loop to match style from one list to price in the other.

1 Like

I think this is a great exercise and is definitely one I may need to reattempt a few times before I fully understand it. I’m struggling quite a bit but was able to get through it by using the hints provided. Probably the hardest coding challenge I’ve come across so far on my ‘Build Web Apps with Flask’ skill path. :sweat_smile:

Taking notes and trying to learn from it.

Hi! I am also struggling with step 12 in Carly’s Clippers. The text:

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 .

I was able to get thru the step but I’m having difficulty understanding what is happening in the code solution:

cuts_under_30 = [ hairstyles[i] for i in range(len(hairstyles)) if new_prices[i] < 30 ]

My specific question:
I’m trying to breakdown how i is being used in the list comprehension. It seems like a neatly folded up conditional and its gently blowing my mind. How ( with range() and i ? ) and where ( within the outer ? ) does the code know that the lists correspond?

A list comprehension is an iterator, or very nearly one. Under the surface Python is iterating.

We construct the data within the list structure, given an iteration variable,

[a + 1 for a in range(10)]    #  iteration variable, `a`

What have we got? A list object consisting of the numbers from 1 to 10. An iterable. That’s what comprehensions produce. An iterable from an iterator, of sorts.

What’s more important to note is that comprehensions are expressions, not constructs so they fit into a lot more places as data.