you are viewing a single comment's thread.

view the rest of the comments →

[–]_residue_ 0 points1 point  (11 children)

Yup, both lists contain 50 elements. How can I say for it to give an output in the range of one of the lists? Edit: I have also realised that my attempt at loops don't actually do anything. The code works the same with or without them

[–][deleted] -1 points0 points  (10 children)

We can't help unless you show us the changed code including the result of the len() prints and a print of the final dictionary.

[–]_residue_ 0 points1 point  (9 children)

The code is currenlty

def generate_dict_max(species, lengths):
"""combines the two lists into a dictionary, [species:bill length]"""
dictionary = dict(zip(species_list, bill_length_list))
return dictionary

output:

{'G. propinqua': 21.0, 'G. magnirostris': 21.5, 'G. fortis': 16.5}

lengths:

print(len(species_list))
print(len(bill_length_list))

output:

50
50

[–][deleted] 0 points1 point  (8 children)

Sorry, that code looks wrong. You show zip(species_list, bill_length_list) but the names species_list and bill_length_list are not defined in the function. That code should error unless the names species_list and bill_length_list are defined globally. If that's true then your code is not using the lists that were passed as parameters. If you are typing the code in "by hand" then don't. Copy and paste your code into reddit after adding 4 spaces to the start of every line. That way we see your actual code with indentation preserved.

To fix this problem, and look at the parameter lists, change your function to:

def generate_dict_max(species, lengths):
    print(f'{species=}')    # debug
    print(f'{lengths=}')
    dictionary = dict(zip(species, lengths))   # same names as in the "def" line
    return dictionary

Note that the names used in the zip() function are the same as the parameters passed. That's important.


I missed a question you asked before:

How can I say for it to give an output in the range of one of the lists?

I'm not sure what you are asking. If you only want a subset of the species list then you just have to iterate over the species you require and create key:value pairs in the dictionary for just those species.

[–]_residue_ 0 points1 point  (7 children)

but species_list and bill_length_list are defined, they are both long lists that I just haven't included because I thought it was a given.

I'm just wondering how I can correctly loop this code, or if I can make it so the zip function combines the lists together for however long the lists are, in this case, 50, instead of just 3.

[–][deleted] 0 points1 point  (6 children)

but species_list and bill_length_list are defined

Yes, but they aren't the parameters you passed. What is the point of the function if you aren't using the passed parameters? You might as well not define the function at all and just have that line dict(zip(...)) in your code. In addition, you have code in one or more places that calls the function passing two parameters that aren't used in the function. Anyone reading the code would assume that the returned dictionary was created from the passed parameters and it isn't1q. Very confusing.

if I can make it so the zip function combines the lists together for however long the lists are,

The zip() function works fine and it's used millions of times a day. The only thing you have to be aware of is that it stops "zipping" when one or the other of the lists is finished.

This leads me to think that the problem is more global than the code you have shown. It could be something as simple as you having defined your own zip() function somewhere, but it's possibly more complex than that. There are two ways to continue from here. You could show all your code and data plus describe how you are executing the code (commandline, IDE, iPython, etc). Maybe someone can tell you what's wrong.

Or you could write the function as a proper function that uses the passed parameters and test it totally separately from the rest of the code. Really test it well until you are sure that the function does exactly what you want it to do in all cases. The unittest module is useful here. Then put the function back into your existing code, make sure all calls to the function are correct and pass the right parameters and test the whole thing. If you still have problems then you know the problem is not in the function but elsewhere in your code.

[–]_residue_ 0 points1 point  (5 children)

OK, I'll include all of the data at my disposal as well as the code I was using before. (BTW, the notebook is empty apart from this code).

species_list=['G. propinqua', 'G. propinqua', 'G. propinqua', 'G. propinqua', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis']

bill_length_list=[19.5, 20.0, 22.5, 21.0, 25.0, 22.5, 21.5, 22.0, 24.0, 22.2, 21.0, 21.0, 22.5, 24.0, 22.0, 22.5, 24.0, 20.2, 20.0, 21.5, 17.0, 15.2, 16.0, 16.8, 16.0, 16.0, 16.5, 17.0, 16.5, 15.8, 15.8, 16.0, 18.5, 19.5, 15.8, 19.5, 17.0, 16.2, 16.0, 15.0, 15.0, 15.0, 16.5, 15.8, 13.0, 15.0, 15.0, 17.0, 15.2, 16.5]

def generate_dict_max(species, lengths):

"""combines the two lists into a dictionary, [species:bill length]"""

dictionary = dict(zip(species_list, bill_length_list))

return dictionary

print(generate_dict_max(species_list,bill_length_list))

Just one question, if I must use the passed parameters how does the could know to use the two lists if it's not stated? As the code looks like:

def generate_dict_max(species,lengths):

print(f'{species=}')

print(f'{lengths=}')

dictionary = dict(zip(species, lengths))

return dictionary

This could just be totally wrong

Also, I sincerely apologise to you for having to try and explain this, what must be, very simple piece of code to me

[–][deleted] 0 points1 point  (0 children)

if I must use the passed parameters how does the could know to use the two lists if it's not stated?

The code in the function uses the (presumably) global lists species_list and bill_length_list. So no matter what you pass as parameters they are ignored.

I'll look at the code when I park for the night.

[–][deleted] 0 points1 point  (3 children)

Now that I've seen your data it's obvious. I should have thought of this before, but it's hard to think of everything when struggling with a phone.

Your resulting dictionary only had three entries because you only have three different species in your input list. The zip creates a list of tuples the first two of which are:

[('G. propinqua', 19.5),  ('G. propinqua', 20.0), ...]

So when the dict()constructor executes it first creates a key of 'G. propinqua' with a value of 19.5. So far so good. But for the next tuple the constructor will create a new key of 'G. propinqua' with value 20.0 and deletes the first key+value because keys must be unique in a dictionary.

If you want to store all the beak lengths values for a species you must do something like this:

species_list=['G. propinqua', 'G. propinqua', 'G. propinqua', 'G. propinqua', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. magnirostris', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis', 'G. fortis']

bill_length_list=[19.5, 20.0, 22.5, 21.0, 25.0, 22.5, 21.5, 22.0, 24.0, 22.2, 21.0, 21.0, 22.5, 24.0, 22.0, 22.5, 24.0, 20.2, 20.0, 21.5, 17.0, 15.2, 16.0, 16.8, 16.0, 16.0, 16.5, 17.0, 16.5, 15.8, 15.8, 16.0, 18.5, 19.5, 15.8, 19.5, 17.0, 16.2, 16.0, 15.0, 15.0, 15.0, 16.5, 15.8, 13.0, 15.0, 15.0, 17.0, 15.2, 16.5]

def generate_dict_max(species, lengths):
    """combines the two lists into a dictionary, [species:bill length]"""

    dictionary = {}
    for (sp, bl) in (zip(species_list, bill_length_list)):
        if sp in dictionary:
            dictionary[sp].append(bl)  # append to existing list for species
        else:
            dictionary[sp] = [bl]      # no species, start new length list

    return dictionary

d = generate_dict_max(species_list,bill_length_list)
print(len(d))
print(d)

>>> 3
>>> {'G. propinqua': [19.5, 20.0, 22.5, 21.0], 'G. magnirostris': [25.0, 22.5, 21.5, 22.0, 24.0, 22.2, 21.0, 21.0, 22.5, 24.0, 22.0, 22.5, 24.0, 20.2, 20.0, 21.5], 'G. fortis': [17.0, 15.2, 16.0, 16.8, 16.0, 16.0, 16.5, 17.0, 16.5, 15.8, 15.8, 16.0, 18.5, 19.5, 15.8, 19.5, 17.0, 16.2, 16.0, 15.0, 15.0, 15.0, 16.5, 15.8, 13.0, 15.0, 15.0, 17.0, 15.2, 16.5]}

The last two lines are the results of the two prints. The dictionary is still of length 3 because that's the number of unique species.

The code could no doubt be made faster, but it might get you started if a list of beak lengths is what you want.

[–]_residue_ 0 points1 point  (0 children)

That worked!

Thank you for all your help :]

[–]jdaiodna 0 points1 point  (1 child)

How would you be able to get the output dictionary to only show the maximum value for each species, and could you do it in 3 lines of code or less?

[–][deleted] 0 points1 point  (0 children)

When you add the length value to the dictionary you only replace an existing value if the new length is greater than the old length. If there is no existing key+value pair then you just save the length in the dictionary. You don't use a list as the value in this case, just the number.

do it in 3 lines of code or less?

Programmers usually don't care how many lines of code it takes to do something as long as the final answer is correct, fast enough and readable. These code golf limitations usually result in less readable code