user2858846
user2858846

Reputation: 49

Find lowest value in a list of dictionaries in python

I want to find and return the minimal value of an id in a string, for example:

find_min_id([{"nonid": "-222", "id": 0}, {"id": -101}])
-101
find_min_id([{’id’: 63, 'id': 42}])
42

So far I have this:

def find_min_id(list):
    return min(list)

but that gives:

{'id': -101}

and I only want the value of the lowest id.

Upvotes: 5

Views: 2515

Answers (6)

BartoszKP
BartoszKP

Reputation: 35891

Another approach, but works where there is no id in the dictionary, and when there is no dictionary with an id at all:

def find_min_id(lst):
    ids = [d['id'] for d in lst if 'id' in d]
    return min(ids) if ids else None

Without exceptions, and without running min for artificially extended list (i.e. the answer which puts maximum floats where an entry isn't an id-entry).

Upvotes: 2

Claudiu
Claudiu

Reputation: 229331

Use the key parameter of min:

def find_min_id(l):
    return min(l, key=lambda d: d.get("id", float('inf')))["id"]

This actually finds the min id, and does it without creating a new list.

The only thing is, the elements in your list might not had an 'id' key. For that reason I had to use .get("id", float('inf')). Thus the function will return inf if there is no id key, which might not be desirable. What min() does when given an empty list is it throws an exception, so we'd probably like to do the same if none of the dicts we pass it have an 'id' key. In that case the min of a generator appoach might indeed be better:

def find_min_id(l):
    return min(d["id"] for d in l if "id" in d)

The other approach would be to check for inf as the result of min, but this is more cumbersome:

import math
def find_min_id(l):
    res = min(l, key=lambda d: d.get("id", float('inf')))["id"]
    if math.isinf(res):
        raise ValueError("No dict has an 'id' key")
    return res

Upvotes: 7

Nafiul Islam
Nafiul Islam

Reputation: 82470

>>> ids = [{"nonid": "-222", "id": 0}, {"id": -101}]
>>> min([val for obj in ids for key, val in obj.items() if key == 'id'])
-101
>>> ids = [{'id': 63}, { 'id': 42}]
>>> min([val for obj in ids for key, val in obj.items() if key == 'id'])
42

Try the above.

You can make this into a function definition:

def find_lowest(ids):
    return min([val for obj in ids for key, val in obj.items() if key == 'id'])

Working example.

Let me explain what I'm doing. Firstly, the min function takes in an iterable object as an argument. So, let me demonstrate:

>>> min([1,2,3,4,6,1,0])
0

So, what this means is this, we are essentially taking the minimum value of the list that we get from this, [val for obj in ids for key, val in obj.items() if key == 'id'].

Now, you might be wondering, well whats happening in there? It might be a little intimidating at first, but thats a list comprehension. Whats that you say? Well, in simple terms its a concise we in which we make a list:

Let me start with be first part, and no its not the beginning of the statement:

for obj in ids

What we are doing here, is iterating over all the dictionary objects in in side of ids. Now, we use that object here:

key, val in obj.items() if key == 'id'

Since object, is a dict, we use the items function to get a generator that gives a tuple of key, value pairs. In an object like this: {'id': 100}, the id would be they key and 100 would be the value. So, we are going over all the items in the dictionary object, and if the key happens to be id, then we append it to the list:

[val

Thats what the first part does. The first part of the list comprehension appends something to the final list, and that is val.

UPDATE:

If for some reason, the list does not containt anything with id as a key, then it will throw a ValueError as min does not accept an empty list, so to remedy this, we can check:

def find_lowest(ids):
    _ret = [val for obj in ids for key, val in obj.items() if key == 'id']
    if _ret:
        return min(_ret)
    else:
        return None

Upvotes: 1

aIKid
aIKid

Reputation: 28252

You are trying to find the 'lowest' dictionaries. What we want is, to find the lowest 'id' value in the list.

def find_min_id(lst):
    return min([d[key] for key in d for d in lst if key=="id"])

Also, avoid using list as a variable name, it overrides the built-in function list().

A little demo:

>>> def find_min_id(lst):
    return min([d[key] for key in d for d in lst if key=="id"])

>>> find_min_id(lst)
-101

Hope this helps!

Upvotes: 1

alko
alko

Reputation: 48317

Following code return None if no id key is in list.

>>> data = [{"nonid": "-222", "id": 0}, {"id": -101}, {"nonid":-200}]
>>> min(filter(lambda x: x is not None, map(lambda x: x.get('id', None),
...    data)) or [None])
-101

Here filter(lambda x: x is not None, ...) filters out dictionaries without id, map(lambda x: x.get('id', None), data) gets all id's from data, and or [None] part treats case when no id key will be found in data.

Upvotes: 1

ajay
ajay

Reputation: 9680

list is a built-in type in Python. don't use it as an identifier

def find_min_id(my_list)  
    id_list = []
    for record in my_list:
        if 'id' in record:
            id_list.append(record['id'])
    return min(id_list)

Upvotes: 0

Related Questions