首页 > 解决方案 > Finding smallest entry in a dictionary, getting last key-value pair instead

问题描述

My textbook asks me to write a function that takes a single dictionary as input and returns the particle that is least likely to be observed, where the key is the particle name and the value is the probability of that particle getting observed. Here is the dictionary:

parts_to_probs = {'proton': 0.21, 'meson': 0.03, 'muon': 0.07, 'neutron': 0.55}

And here is my function with the docstring:

def least_likely(parts_to_probs: dict) -> str:
    """Return the particle from parts_to_probs that is least probable to be
    observed.

    >>> least_likely({'proton': 0.21, 'meson': 0.03, 'muon': 0.07, 'neutron': 0.55}) 

    ('meson', 0.03)
    """

    smallest = 1
    name = ''

    for particle in parts_to_probs:           
        probability = parts_to_probs[particle] 
        if probability < smallest:
            smallest = probability
            name = particle

    return (particle, probability)

print(least_likely(parts_to_probs))

Now when I run this program, it always prints out the last key/value pair from the dictionary, regardless if it has the smallest probability or not. I'm really not sure what I have to change, since the for loop should stop after the second loop.

Since 'muon' has a probability of 0.07, probability is not < smallest (0.03 after second loop).

标签: pythondictionary

解决方案


You are returning the last particle and probability, not smallest and name:

return (particle, probability)

particle and probability are the variables from your loop:

for particle in parts_to_probs:
    probability = parts_to_probs[particle]

and the particle and probability variables are not cleared when a for loop ends (Python doesn't have block scope, the variables exist for the duration of the function).

Your loop body updates the smallest and name variables correctly, so return those values:

return (name, smallest)

The corrected function:

def least_likely(parts_to_probs: dict) -> str:
    """Return the particle from parts_to_probs that is least probable to be
    observed.

    >>> least_likely({'proton': 0.21, 'meson': 0.03, 'muon': 0.07, 'neutron': 0.55}) 

    ('meson', 0.03)
    """

    smallest = 1
    name = ''

    for particle in parts_to_probs:           
        probability = parts_to_probs[particle] 
        if probability < smallest:
            smallest = probability
            name = particle

    return (name, smallest)

Some things you are probably going to be taught further on:

  • Where you use for particle in parts_to_probs:, you are iterating over the dictionary keys. You can also iterate over the items, or key-value pairs, with the dict.items() method. This saves you a separate probability = parts_to_probs[particle] statement:

    for particle, probability in parts_to_probs.items():
    
  • The built-in min() function can also do the work your function is doing, provided you teach it how to compare each key-value pair against others to find the smallest. That's the job of the key argument to the function, it is called with each item and you are supposed to return the value to use in the comparisons. A function that takes the second element of each (key, value) pair would be great for this, and lambda pair: pair[1] is a compact way of spelling out such a function:

    min(parts_to_probs.items(), key=lambda pair: pair[1], default=(None, 1))
    

    but you could also use a operator.itemgetter() object:

    from operator import itemgetter
    min(parts_to_probs.items(), key=itemgetter(1), default=(None, 1))
    

推荐阅读