Reputation: 3383
I have a dictionary where values are list of not unique values and associated with various keys.
mydict = {120: ["foo", "bar", "cat"], 125: ["dog", "foo", "bar"]}
I have a set of the values in the dictionary
myset = set(['foo', 'bar', 'cat', 'dog'])
I want to return and print only 1 key for each value in the dictionary and with the condition that this key is the largest number to which the value corresponds in the dictionary. To clarify what I mean, this is the result I would like to achieve:
120: "cat"
125: "dog"
125: 'foo'
125: 'bar'
So every value gets printed only once and only with it's largest corresponding number. I've been able to print each value present in the set together with the key but wonder how to build in the conditional aspect:
result = ''
for i in set:
result += "%s\t%s" % (i, [key for key in dict if i in dict[key]])
Upvotes: 0
Views: 900
Reputation: 1123400
The most efficient solution is to first collect the maximum key per unique value; you can filter on your set beforehand or re-use the resulting mapping for other sets.
This is a O(N) (linear time) solution, where N is the total number of values in the dictionary. Pre-filtering brings it down below that as you only consider values in your set. Compare that to Jon's answer which uses sorting; a O(NlogN) algorithm.
Post-selection of the set keys looks like:
max_key = {}
for key, values in mydict.iteritems():
for value in values:
if key > max_key.get(value, float('-inf')):
max_key[value] = key
result = {val: max_key[val] for val in myset}
You can use the max_key
mapping to produce results for any set now.
Pre-filtering looks like
max_key = {}
for key, values in mydict.iteritems():
for value in myset.intersection(values):
if key > max_key.get(value, float('-inf')):
max_key[value] = key
result = {key: val for val, key in max_key.iteritems()}
but you'd have to re-run the whole algorithm for each new set of values.
Upvotes: 0
Reputation: 142206
You don't need to build an intermediate set, you can build a generator over the dict
then sort the items and utilise the fact that the last element of a key/value pair will be the highest key entry, and pass it to a dict
constructor, eg:
mydict = {120: ["foo", "bar", "cat"], 125: ["dog", "foo", "bar"]}
result = dict(sorted(((v, k) for k in mydict for v in mydict[k])))
# {'foo': 125, 'bar': 125, 'dog': 125, 'cat': 120}
Then output the result
values as appropriate.
If you did really want to filter on some key values, then you can use:
required = {'cat', 'foo'}
result = dict(sorted(((v, k) for k in mydict for v in mydict[k] if v in required)))
# {'foo': 125, 'cat': 120}
Upvotes: 1
Reputation: 10252
if __name__ == "__main__":
mydict = {120: ["foo", "bar", "cat"], 125: ["dog", "foo", "bar"]}
tempdict = {}
for key, value in mydict.items():
for item in value:
tempdict[item] = key
myset = set(['foo', 'bar', 'cat', 'dog'])
for item in myset:
if item in tempdict.keys():
print "%d: %s" % (tempdict[item], item)
the output is:
125: foo
125: bar
125: dog
120: cat
Upvotes: 0
Reputation: 704
More clear and convenient solution, i think.
out = {}
for value in myset:
out[val] = max([key for key, values in mydict.iteritems() if value in values])
output:
{'bar': 125, 'cat': 120, 'dog': 125, 'foo': 125}
Upvotes: 0
Reputation:
Try this:
from itertools import chain
mydict = {120: ['foo', 'bar', 'cat'], 125: ['dog', 'foo', 'bar']}
values = set(chain(* [v for k, v in mydict.items()]))
# values == {'bar', 'cat', 'dog', 'foo'}
for v in values:
m = 0
for k, vl in mydict.items():
if v in vl and k > m:
m = k
print(v + " " + str(m))
Output:
dog 125
bar 125
cat 120
foo 125
Upvotes: 0