function that pairs keys of two dictionaries based on how close their values are?

All we need is an easy explanation of the problem, so here it is.

I want to make a function that takes two dictionaries as inputs, where the keys of the dictionaries are strings and the values are ints or floats. It should only use list comprehensions, for-loops, and if statements without imports. for example, an input should look like this:

nearest_location({'person_a': 10, 'person_b': 12},{'place_c': 11, 'place_d': 12})

the goal of this function is to return a single new dictionary comprised of sets of the keys from dictionary 1 and keys from dictionary 2, which are paired based on how close their corresponding values are.

for instance, the input above should return {'person_a': 'place_c', 'person_b': 'place_d'}. this is because the value for 'person_a', 10, in dictionary 1 is closest to the value for 'place_c', 11. The same can be said for the values for 'person_b‘ and 'place_d'. Note that the amount of entires in the new dictionary will always be the amount of entries in dictionary 1, regardless of how many entries are in dictionary 2.

Next, I would like to account for loopholes and exceptions in the function:

for example,

nearest_location({'person_a':10, 'person_b':11, 'person_c':12},{'place_a':10,'place_b':10}) 

should return

({'person_a':'place_a','person_b':'place_a','person_c':'place_a'])

all the values in dictionary 2 are the same, so instead the first key in alphabetical order from dictionary 2 should be paired which each key in dictionary 1 instead.

What I have tried:

the code itself is short and not a function but I wanted to try it as a proof of concept. This method uses a for-loop but I would like to use list comprehension in my function.

people = {'person_a': 10, 'person_b': 12}
places = {'place_c': 11, 'place_d': 12}

for i in people:
    for j in places:
        print([i, j], abs(people[i] - places[j]))

the output of this is

['person_a', 'place_c'] 1
['person_a', 'place_d'] 2
['person_b', 'place_c'] 1
['person_b', 'place_d'] 0

as you can see, this does not print the dictionary that I want for my functions output. It does however calculate the distance between each key in dictionary 1 and 2. I wanted to use this to somehow get the minimum values an assemble a dictionary from that.

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

Given the question, I would say a simple solution for this would be

def nearest_location(people, places):
    nearest_locations = {}
    for i in people:
        nearest_dist = float("inf")
        nearest_point = None
        for place, location in sorted(places.items()):
            if (abs(people[i]-location)<nearest_dist):
                nearest_dist = abs(people[i]-location)
                nearest_point = place
        nearest_locations[i]=nearest_point
    return nearest_locations

I am not entirely sure what you mean by "It should only use list comprehensions and for-loops without imports". So if we are not allowed to use "if statements", we can do this using list comprehension

def nearest_location(people, places):
    nearest_locations = {}
    for i in people:
        nearest_locations[i]  = sorted([(abs(people[i]-location), place) for place, location in places.items()])[0][1]
    return nearest_locations

or

def nearest_location(people, places):
    return {i:sorted([(abs(people[i]-location), place) for place, location in places.items()])[0][1] for i in people}

Method 2

def nearest_location(people, places):
    assignments = dict()
    for person, person_location in people.items():
        closest_place, best_distance = '', float('inf')
        for place, place_location in places.items():
            distance = abs(place_location - person_location)
            if distance < best_distance:
                closest_place, best_distance = place, distance
            elif distance == best_distance:
                if place < closest_place:
                    closest_place = place
        assignments[person] = closest_place
    return assignments

nearest_location({'person_a':10, 'person_b':11, 'person_c':12},{'place_a':10,'place_b':10}) 

produces the desired output

{'person_a': 'place_a', 'person_b': 'place_a', 'person_c': 'place_a'}

Whenever, for a given person, there exist two places yielding the same distance, whichever with smaller alphabetical order is used.

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply