returning min from dict values where there are more than one zeros

100 Views Asked by At

I have a weird situation with a dict which looks like so:

a={
    "key1":[{"a":10,"b":10,"d":0},{"a":100,"b":100,"d":1},{"a":1000,"b":1000,"d":0}], 
    "key2":[{"a":18,"b":135,"d":0},{"a":135,"b":154,"d":10},{"a":123,"b":145,"d":0}],
    "key3":[{"a":145,"b":1455,"d":0},{"a":15,"b":12,"d":1},{"a":14,"b":51,"d":10}]
}

I can get the min by key doing this:

[min(group, key=itemgetter("d")) for group in a.values()]
[{'a': 10, 'b': 10, 'd': 0}, 
 {'a': 18, 'b': 135, 'd': 0}, 
 {'a': 145, 'b': 1455, 'd': 0}
]

However this misses entries where where minimum value is more than one zero. So, I would like it to return:

[{'a': 10, 'b': 10, 'd': 0},
 {"a":1000,"b":1000,"d":0},
 {'a': 18, 'b': 135, 'd': 0}, {"a":123,"b":145,"d":0},
 {'a': 145, 'b': 1455, 'd': 0}
]

How can I force this condition

3

There are 3 best solutions below

0
On BEST ANSWER

You need to first get the minimum value of d in each group, then filter the group to the elements with that value of d.

result = []
for group in a.values():
    dmin = min(group, key=itemgetter("d"))['d']
    result.extend(x for x in group if x['d'] == dmin)
1
On

Code:

min_d_values = min((entry for group in a.values() for entry in group), key=itemgetter("d"))
result = [entry for entry in (entry for group in a.values() for entry in group) if entry["d"] == min_d_values["d"]]
print(result)

Output:

[{'a': 10, 'b': 10, 'd': 0}, {'a': 1000, 'b': 1000, 'd': 0}, {'a': 18, 'b': 135, 'd': 0}, {'a': 123, 'b': 145, 'd': 0}, {'a': 145, 'b': 1455, 'd': 0}]
0
On

Generator approach to collect all minimums from inner sublists:

def min_all(d):
    func = itemgetter("d")
    for group in d.values():
        it = iter(sorted(group, key=func))  # iterator of sorted dicts
        min_ = next(it) # initial minimum
        yield min_
        while (m := next(it, {})).get('d') == min_['d']:
            yield m

print(list(min_all(a)))

[{'a': 10, 'b': 10, 'd': 0},
 {'a': 1000, 'b': 1000, 'd': 0},
 {'a': 18, 'b': 135, 'd': 0},
 {'a': 123, 'b': 145, 'd': 0},
 {'a': 145, 'b': 1455, 'd': 0}]

Note, while other solutions based on min+filter approach run in O(2 * N) on sublist level, this approach gives O(k + N log N), where N is the number of items in sublist and k is a variable amount of minimum values. If you care about time/space complexity.