简体   繁体   中英

Get key with minimum value on a dictionary that contains 'None' / 'False' values

My project is a rudimentar roaming AI. When it has food within it's awareness range it heads toward it. If it has more than one food, it should choose the nearest.

I'm storing the foods on a dict as keys, and the value assigned to the key is the last known distance to said food. Then i check the dict for the food with the minimum distance in order to head towards it.

The problem is that foods outside range are being assigned with the value None (also tried False), and when using

min(self.vision, key=self.vision.get)

it returns the first key with None/False value that it finds. By testing on an online compiler I discovered that on older python versions there's this error:

TypeError: unorderable types: NoneType() < float()

And i guess it nows consider None type to be always lesser than numbers (also tested with ints).

I'm trying to combine lambdas, filters, lists, mins, maps and other functions, but i guess i'm actually dumb. I always get the value back instead of the key, or end up with a filtered list that helps nothing.

I also don't like the idea of creating two dicts, such as 'seen' and 'unseen' foods, though it's a real possibility.

MINIMAL REPRODUCIBLE EXAMPLE: (comment/uncomment third line from bottom to get the error)

class Test:
    def __init__(self,x,y):
        self.x, self.y = x,y
x = {}

for i in range(3):
    for j in range(3):
        x[Test(i,j)] = (i+j)

# x[Test(9,9)] = None
m = min(x, key=x.get)
print(m.x,m.y)

A simple way to do it: create tuples of (distance, item) excluding the ones with None , and get the min out of it:

food = {'bread': 3, 'apple':2, 'pancake': None, 'ham':1}

reachable = [(distance, item) for item, distance in food.items() if distance is not None]
closest = min(reachable)[1]
print(closest)
# ham

Putting the distance first in the tuples allows them to be sorted by distance first without having to specify a sorting key.

Okay, thanks for all comments, found out a neat sollution on a social media python group!

Just uploaded the full project on github! Here's the link if someone wants to mess with it: https://github.com/ParovSt/A-Bullet-Called-Life/blob/master/README.md

Here's the solution some guy showed me:

min(x, key = lambda k: x[k] if x[k] != None else float('inf'))

and here is what i came around the problem before this solution:

for f in foods:
    if distPerPoints((self.x,self.y),f.pos) < self.awareness:
        self.vision[f] = distPerPoints((self.x,self.y),f.pos)
    else:
        #ignores completely each food out of range
        if f in self.vision:
            del self.vision[f]
#[...]

    self.target = min(self.vision, key=self.vision.get)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM