kauray
kauray

Reputation: 719

Finding minimum value from a dictionary whose values are lists of objects

I have a list of Python Objects of type class Service. There is another dictionary grps where the objects are grouped according to a data member. Objects in the same group have exactly the same value for the data member according to which it is grouped.

from collections import defaultdict
class service:
    def __init__(self, tasknum, candidatenum, features, cost):
        self.tasknum = tasknum
        self.candidatenum = candidatenum
        self.features = features
        self.cost = cost

s11 = service(1,1, features = [1], cost = 30)
s12 = service(1,2, features = [1], cost = 50)
s13 = service(1,3, features = [1], cost = 70)
s14 = service(1,4, features = [1], cost = 200)
s15 = service(1,5, features = [2], cost = 20)

lst = []
lst.append(s11)
lst.append(s12)
lst.append(s13)
lst.append(s14)
lst.append(s15)

grps = defaultdict(list)
for x in lst:
    grps[tuple(x.features)].append(x)

In the above, there are two groups, one corresponding to features = [1], and one corresponding to features = [2].

defaultdict(<class 'list'>, {(1,): [<__main__.service object at 0x7efe19a2d6d8>, <__main__.service object at 0x7efe19a2d4e0>, <__main__.service object at 0x7efe1d7e9550>, <__main__.service object at 0x7efe1d7e9588>], (2,): [<__main__.service object at 0x7efe1d7e95c0>]})

For each such group, I would like to return a service object having the minimum cost value, that is, in the above, the first group would return s11 service and the second group would return s15 service since that is the only object in the group.

And is there any better way to do this without using the dictionary, like can this be done by just using lists?

Upvotes: 1

Views: 644

Answers (3)

Mark
Mark

Reputation: 92450

In a list comprehension you can call min() on each member of the groups and use a key that gets the cost attribute. operator.attrgetter handy for this:

from operator import attrgetter
# array of min-cost services
mins = [min(g, key = attrgetter('cost')) for g in grps.values()]

# just the costs
[c.cost for c in mins] # [30, 20]

Upvotes: 4

Devesh Kumar Singh
Devesh Kumar Singh

Reputation: 20500

You can just call min() on each sublist on the cost attribute, and append those objects to a list. min_costs will be the objects with mimimum costs.

#List to hold all objects with min costs
min_costs = []

for k, v in grps.items():
    # Calculate minimum for all sublists on cost attribute
    min_costs.append(min(v, key=lambda x:x.cost))

#Print the costs of objects with min costs
print([c.cost for c in min_costs])
#[30, 20]

A one liner list-comprehension for the same will be

min_costs = [min(v, key=lambda x:x.cost) for v in grps.values()]

Upvotes: 1

Austin
Austin

Reputation: 26039

Now that you have a dictionary, find the object having minimum cost with min and its key argument:

for k, v in grps.items():
    print(min(v, key=lambda x: x.cost))

# <__main__.service object at 0xeac0f090>
# <__main__.service object at 0xeac0f110> 

Upvotes: 1

Related Questions