Help me understand how lists and dictionaries are built


#1



https://www.codecademy.com/en/courses/python-beginner-en-pwmb1/2/2?curriculum_id=4f89dab3d788890003000096

So, I don't have a problem completing the task here, I'm just curious because I can't understand how new information is added to lists and dictionaries. In the first example, when run, the program shows that the dictionary is ordered:{'a': 48.75, 'Chicken Alfredo': 14.5, 'c': 1.5, 'b': 32.6}, but why? I expected them to be in the order that they were added to the dictionary. Having tested several different variations, it seems almost random.

My second question is maybe related. The second bit of code is something I put together on the last exercise just messing around, but I found something that I didn't understand. In the third loop, which should grab each sequential pair from the first list and add them, it seems to start from the end of the list. I discovered this when the limit on the length of the final list was too short and the expected first results didn't exist. It also affects the variable 'l', which should correspond to the location after 'n', the current location for the loop. But it didn't work correctly with(n + 1), instead with(n - 1). I cruised google for a little while but actually didn't understand how to phrase my question and couldn't figure anything out. Is it just standard that loops iterate lists from right to left or I'm not understanding?
Anyway, I guess I don't understand how loops operate at all, that is, I don't, of course, know how to use them well, but I think it would be useful to understand what they are doing. Links appreciated.

Thanks


menu = {} # Empty dictionary
menu['Chicken Alfredo'] = 14.50 # Adding new key-value pair
print menu['Chicken Alfredo']

menu['a'] = 48.75
menu['b'] = 32.6
menu['c'] = 1.5


print "There are " + str(len(menu)) + " items on the menu."
print menu


--------------------------------

a_list = [] #list to be populated linearly
b_list = [] #list to be populated with sum of squares of subsequent vrbls in a_list
c_list = []

while len(a_list) < 10:             #populate a list up to ten
    a_list.append(len(a_list) + 1)

for n in a_list:                    #generate the squares of a_list
    c_list.append(n ** 2)

for n in a_list:                    #add each subsequent pair of squares
    if len(b_list) < (len(a_list)- 1):
        l = a_list[n]
        f = a_list[n - 1]           #WHY MINUS
        b_list.append(l ** 2 + f ** 2)
    else:
        break
                                    #display lists
print a_list
print c_list
print b_list


#2

dict is not ordered, so it can't be in the wrong order, because that requires being in some order, you can read about hash maps if you want to know more than that

Lists iterate from their first index to their last, in order. You can observe this by printing out the current element each time in your loop

You will need to reconsider what n represents in your third loop, you're using it to access lists by index, but what makes you say that the list has an element at position n? How does n relate to your list? Valid reasoning would be that you're counting from 0 up to the length-1, which are all valid indexes. But that's not what you are doing, is it, so how then would you argue that n is ok to use as index?

Further, if you were to iterate through all indexes, then adding or subtracting 1 means that for the last or first element you will be attempting to access elements outside the list


#3

Thanks.
I understand, changed it to:

a_list = [] #list to be populated linearly
b_list = [] #list to be populated with sum of squares of subsequent vrbls in a_list
c_list = []

while len(a_list) < 10:             #populate a list up to ten
    a_list.append(len(a_list) + 1)

for n in a_list:                    #generate the squares of a_list
    c_list.append(n ** 2)

for n in a_list:                    #add each subsequent pair of squares
    if len(b_list) < (len(a_list) - 1):
        f = a_list.index(n)
        l = a_list[f + 1]
        b_list.append(n ** 2 + l ** 2)
    else:
        break
                                    #display lists
print a_list
print c_list
print b_list

What I'll really have to think about later is why it did what I wanted when it was the other way...


#4

If you search through a list to find the position of a value, then you may not get the position you wanted if there are multiple instances of the same value. (It's also a whole lot of work that you wouldn't be doing manually, particularly not for a long list because for each value you would need to start at the front and count how far you've gone

Don't ever settle for "seems to work", don't leave anything until you can explain why it's correct. You'll still get things wrong, but you'll certainly get a whole lot more things wrong by not having followed a plan, things don't go "click" and do what you want, the computer has no clue. You have to see things through or you're running something that nobody designed, it's like taking a photo of the sky, saving the image, and executing the image like a program. Does that do what you want? It might, but there's no way you can reason about it, it's probably not doing what you want, why would it?

Not knowing what your code did is.. a bug. Because that means the code doesn't act as you intend. Your program should do nothing less than exactly what you want.


#5

Do you mean that"

        f = a_list.index(n)
        l = a_list[f + 1]

is a bad way to try to find the current iterating value and the subsequent value in the list, because the value 'n' might appear more than once?

I understand your opinions and appreciate them, but at the moment, I barely understand the tools and have confused some of their uses. I'm still gonna mess around with them.
I even wrote a plan, as far as I could, and then tried to understand what I would need for each process.


#6

In this particular case, it wouldn't, because they're all unique, right? But then again, you might have squares of negative numbers later on, who knows - you won't be able to write the code any better by limiting it it to only being valid for unique values, not in this case. (There's still a real effect of having to iterate through on average half the list once for each position, as you use longer and longer lists, that would quickly grow into more work than the rest of the loop is doing)

You're not doing something to each value, you're doing something at each position.

So what you would do is to find a way to generate each position (this would be a series of integers) and then an action to do for each position.

In the original code, the values themselves were used as positions. They're not that. But you did have values counting from 1 to 10, so they could be interpreted as positions, but that won't work out for zebras. Zebras, or whatever other value that just can't be interpreted as positions by mistake. Or worse yet, if you have something that can be interpreted as valid positions almost all the time, but fails very rarely. That would be a hard-to-find bug.


#7

Cool! Thanks for the knowledge/perspective.


#8

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.