3

How can I use two keys in Python builtin min/max functions?

For example, I have a list of dicts (they serve as counters) like this:

[{88: 3, 68: 0, 6: 0}, {88: 2, 68: 1, 6: 0}, {88: 3, 68: 0, 6: 1}, 
 {88: 2, 68: 1, 6: 1}, {88: 3, 68: 0, 6: 2}, {88: 2, 68: 1, 6: 2}, 
 {88: 2, 68: 0, 6: 3}, {88: 2, 68: 1, 6: 0}, {88: 1, 68: 2, 6: 0}, 
 {88: 2, 68: 1, 6: 1}]

and I want to know which counter has the minimum cost:

cost = lambda d: sum(k * v for k, v in d.items())

as well as the minimum count:

count = lambda d: sum(d.values())

I know how to do it in normal code. I just wonder if there is any pythonic way to do this.

Selcuk
  • 57,004
  • 12
  • 102
  • 110
Seaky
  • 239
  • 2
  • 13
  • 1
    By "as well as" do you mean `and` or min of sum or least of either? – Mark Oct 30 '19 at 04:14
  • @MarkMeyer I mean and. It should have the minimal cost and the minimal count. – Seaky Oct 30 '19 at 04:17
  • @MarkMeyer But you are doing int and int which would mostly return 1. I am thinking maybe like `lambda d: (cost(d), count(d))`. – Seaky Oct 30 '19 at 04:20

1 Answers1

2

You should use the exact same method you would use for sorting:

>>> my_list = [{88: 3, 68: 0, 6: 0}, {88: 2, 68: 1, 6: 0}, {88: 3, 68: 0, 6: 1},
               {88: 2, 68: 1, 6: 1}, {88: 3, 68: 0, 6: 2}, {88: 2, 68: 1, 6: 2},
               {88: 2, 68: 0, 6: 3}, {88: 2, 68: 1, 6: 0}, {88: 1, 68: 2, 6: 0},
               {88: 2, 68: 1, 6: 1}]

>>> sorted(my_list, key=lambda d: (sum(k * v for k, v in d.items()), sum(d.values())))
[{88: 2, 68: 0, 6: 3}, {88: 1, 68: 2, 6: 0}, {88: 2, 68: 1, 6: 0}, {88: 2, 68: 1, 6: 0}, 
 {88: 2, 68: 1, 6: 1}, {88: 2, 68: 1, 6: 1}, {88: 2, 68: 1, 6: 2}, {88: 3, 68: 0, 6: 0},
 {88: 3, 68: 0, 6: 1}, {88: 3, 68: 0, 6: 2}]

>>> min(my_list, key=lambda d: (sum(k * v for k, v in d.items()), sum(d.values())))
{88: 2, 68: 0, 6: 3}

>>> max(my_list, key=lambda d: (sum(k * v for k, v in d.items()), sum(d.values())))
{88: 3, 68: 0, 6: 2}
Selcuk
  • 57,004
  • 12
  • 102
  • 110