# How to find the smallest unique value in the dictionary?

Still learning. So strongly do not scold. Trying to figure out with dictionaries.
Set myself this problem:
Dictionary: name value (20 pieces)
Values can be repeated
How to find the smallest unique value in the dictionary?
For example:
nick=23, light=26, Nastia=45, Sanya=23
Expected result => the world=26

Until I got:
``````a = "roma"
b = "nastia"
c = "sasha"

aa = 12
bb = 23
cc = 45

qw = {a:aa, b:bb, c:cc}

if qw[a] < qw[b] and qw[a] < qw[c]:
print a, qw.get(a)
elif qw[a] == qw[b] or qw[a] == qw[c] or qw[b] == qw[c]:
print("not smallest")
elif qw[b] < qw[a] and qw[b] < qw[c]:
print b, qw.get(b)
else:
print c, qw.get(c)``````

Now, understand that if you add a dictionary for another 10-20 J. values will be fully and check for uniqueness - how?
September 19th 19 at 12:07
September 19th 19 at 12:09
Solution
The most simple and effective solution, without unnecessary actions:
``````from collections import Counter

def min_unique(dictionary):
minval, result = float('inf'), None
counter = Counter(dictionary.itervalues())
for key, val in dictionary.iteritems():
if (val < minval) and (counter[val] == 1):
minval = val
result = (key, val)
return result

data = {'a': 23, 'b': 26, 'c': 45, 'd': 23}
min_unique print(data)``````

Or this:
``````from operator import itemgetter
from itertools import ifilter

def min_unique(dictionary):
inverted = dict()
for key, value in dictionary.iteritems():
inverted[value] = None if value else key in inverted
filtered = ifilter(itemgetter(1), inverted.iteritems())
try:
value, key = min(filtered, key=itemgetter(0))
except ValueError:
value, key = None, None
return key, value``````

Another interesting option with iterators (bottleneck - sort):
``````from operator import itemgetter
from itertools import groupby

def min_unique(dictionary, ig=itemgetter(1)):
grouped = groupby(sorted(dictionary.viewitems(), key=ig), key=ig)
for key, entries in grouped:
entry = entries.next()
try:
entries.next()
except StopIteration:
return entry
else:
continue``````
Hats off to you, your new solution is elegant, simple and does not require the use of python-specific bodies. - dax56 commented on September 19th 19 at 12:12
: Thank you :) - Rhea.Cummings commented on September 19th 19 at 12:15
September 19th 19 at 12:11
You need to try to write a generic algorithm for solving the problem, and not to cycle through valid options. This can be done even without the use of a particular programming language, using only logic statements. For example: first, count the number of occurrences of each value in the dictionary (see counter in the code). Then, choose the smallest unique value. For this it is necessary to filter out the unique array, then sort it ascending and take the first element (see lowest_unique = (sorted([k for k in counter if counter[k] == 1]) or [None])[0]). Now you need to find the key in the initial dictionary corresponding to the minimum value. Of course, you can iterate over all keys in dictionary to check their meanings, but it is long. If you make a reflection of the initial dictionary (the coup, flip), the given value of the key will be to find the simplest treatment flipped_dict[lowest_unique]. Making the revolution: flipped_dict = dict(zip(initial_dict.values () initial_dict.keys())).

Full version code:
``````initial_dict = {'Foo': 23, 'Bar': 26, 'Baz': 45, 'Bang': 23}
flipped_dict = dict(zip(initial_dict.values () initial_dict.keys()))
# print(flipped_dict)
# {26: 'Bar', 45: 'Baz', 23: 'Foo'}

counter = {}
for k in initial_dict:
val = initial_dict[k]
counter[val] = counter.get(val, 0) + 1
# print(counter)
# {26: 1, 45: 1, 23: 2}

lowest_unique = (sorted([k for k in counter if counter[k] == 1]) or [None])[0]
if lowest_unique is None:
else:
print("Found [%s]->[%s]" % (flipped_dict[lowest_unique], lowest_unique))``````
Your response is a Prime example of how the wrong reasoning about the "common" solution of the problem lead to writing inefficient and hard to read bad code. In this task, it is only a sort, and all. No filtrations and investirovanii dictionary, not to mention zip. And You've built at least 4 of the list that are not needed. Instead of keys() and values() could use one iteritems(), and even better - a dictionary view (which, unfortunately, is rare in the literature). - dax56 commented on September 19th 19 at 12:14
: speeches about optimal code was not. Question author just learning to program. Right now he needs to deal with the construction of algorithms. Yes, your solution is quick - but look how many new concepts will have to meet the author of the question? 2 new modules, iterators, exception. This pythonic code, Yes, I wrote rather just understand the algorithm in pseudocode. - Rhea.Cummings commented on September 19th 19 at 12:17
Ivan, I try to give quite complex responses that newbies could get acquainted with new concepts. Simple Pascal-style on the toaster in abundance :) Although in this case the simplest solution is the most effective (I was like). - Rhea.Cummings commented on September 19th 19 at 12:20
: Yes, your new solution is just great. I have a similar, but apparently not-so-radical views, that's why I said in my response, only zip and list comprehension. - dax56 commented on September 19th 19 at 12:23
September 19th 19 at 12:13
Not claim to be ideal solution and the maximum program execution speed, I myself am a novice.
``````d = {'a': 21, 'b': 5, 'c': 7, 'd': 5, 'e': 10}
u = {k: v for k, v in d.items() if tuple(d.values()).count(v) < 2}
print(min(u.items(), key=lambda i: i[1])[0])``````

Some explanations:
1. d - the dictionary
2. u - shaped slowly, in which were the only elements with unique values
3. Using the min function computed element by comparing the value of values (not keys), we get a tuple of the form (key, value) and return and refund [0] element, that is key.
---
If you use python2.7, then instead of u.itŠµmes(), it is better to use u.iteritems()
1) Why use a tuple, list, too, if there is a function count()?
2) Generally search very inefficient, but will leave it with that.
3) d.values().count it makes sense to identify separately, so as not to cause d.values() each iteration. And generally dotted notation in a loop is not recommended: https://wiki.python.org/moin/PythonSpeed/Performan...
4), min() will cause an error in the case where no unique values.
5) Instead of the lambda is better to use operator.itemgetter(1)

How to increase speed in 2+ times:

``````>>> d = {'a': 21, 'b': 5, 'c': 7, 'd': 5, 'e': 10}
>>> def v1(d=d):
return {k: v for k, v in d.items() if d.values().count(v) == 1}
>>> def v2(d=d, cnt=d.values().count):
{k: v for k, v in d.items() if cnt(v) == 1}
>>> def v3(d=d, cnt=d.values().count):
{k: v for k, v in d.viewitems() if cnt(v) == 1}
>>> from timeit import timeit
>>> timeit(v1, number=1000000)
9.940651956859298
>>> timeit(v2, number=1000000)
6.061919530989137
>>> timeit(v3, number=1000000)
4.280532062150144``````
- dax56 commented on September 19th 19 at 12:16
Thanks for the explanation. I still haven't measured the performance and about itemgetter and viewitems did not know. - Rhea.Cummings commented on September 19th 19 at 12:19
: here is not the best use viewitems(), you can replace iteritems() - Rhea.Cummings commented on September 19th 19 at 12:22
: A performance measure, it is excellent and teaches you to write efficient code. And iterators/generators to use wherever possible. - dax56 commented on September 19th 19 at 12:25
Well for the first try on edx about them already told, and in python3, many things become generators, in contrast to python2. - Rhea.Cummings commented on September 19th 19 at 12:28

Find more questions by tags Python