help - iter & dict

Alistair King alistair.king at helsinki.fi
Fri Aug 4 06:16:42 EDT 2006


Simon Forman wrote:
> aking at mappi.helsinki.fi wrote:
>   
>> Dear Python people,
>>
>> im a newbie to python and here...so hello!
>>     
>
> Hi Ali, and welcome.
>
>   
>> Im trying to iterate through values in a dictionary so i can find the
>> closest value and then extract the key for that value....what ive done so far:
>>
>> def pcloop(dictionary, exvalue):
>>         z = dictionary.itervalues()
>>         y = z - exvalue
>>         v = (y*y)**1/2
>>         if v < 0.001:
>>             u = dictionary.get[z]
>>         return u
>>
>>
>> ive been working off a couple of books and this is the best i can get it in
>> short time. I was trying to define a function (its my first!) so that i
>> could apply to several 'dictionary's and 'exvalue's. The best ive been able
>> to come up with is iterating over the dictionary values, subtracting the
>> exvalue, squaring then root squaring to render positive and applying an
>> error (0.001) which is not the ideal solution i want. Is there any easy way
>> to iterate through dictionary values and return the key for the minimum. Or
>> can someone tell me where im going wrong with this def & loop.
>>
>> regards all
>>
>> Ali
>>     
>
> You're doing many interesting things wrong here.  :-)  I'm going to
> take them slightly out of order.
>
> First, very ingenious way to get the absolute value of a number, but
> there are a few issues with this that you should know about.
>
> For instance, just as multiplication and division take precedence over
> addition and subtraction, the "power" operator ** take precedence over
> division,  so what you're really doing above is
>
> ((y*y)**1)/2
>
> rather than
>
> (y*y)**(1/2)
>
> However, the above still wouldn't work correctly because of the way
> python handles integer division.  1/2 == 0 in python, try it at the
> interactive prompt and you'll see.
>
> So, you'd have to change at least one of the division's operands to
> float to get the proper result you desire.
>
> (y*y)**(1./2)
>
> Except that you should actually use the (built in) abs() function,
>
> v = abs(y)
>
> :-)
>
> Next, the itervalues() method of dicts does not return a number, but
> rather a "dictionary-valueiterator" object, as you can see from this:
>
> |>> d = {}
> |>> z = d.itervalues()
> |>> z
> <dictionary-valueiterator object at 0xb6f23c00>
>
> In order to get values out of it you need to iterate over it like so:
>
> for z in d.itervalues():
>     # Do something with z's here...
>
> You could also get both the keys and values at the same time by
> iterating like so:
>
> for k, z in d.iteritems():
>     # Do something with k's and z's here...
>
> (I'll come back to that.)
>
> Now, a little further down in your function, you seem to want to use
> the z value with the get() method of the dict to retrieve the key.
> This won't work.
>
> First, you're not *calling* the get method (that uses ()'s) you're
> *subscripting* it (that uses []'s.)  If your code got this far, it
> would break here.
>
> |
>
> In fact, there is no easy way to get the key from a dict given a value.
> Dicts work the other way around.  (You basically have to iterate
> through the values *and* keys, one pair at a time, testing each value
> as you go.  This is very slow, compared to getting the value given a
> key.)
>
> value = d[key]
>
> This is extremely fast.  It's pretty much the whole point of a
> dictionary that this is very fast.
>
> So, when you build the dict that you pass in to your function, you
> might want to build it the other way round, i.e. make the keys the
> values and the values keys.  However, you might not and here's why:
>
> Dicts can only have one key of any given value of key.  Look:
>
> |>> d = {1: 'a', 1: 'b'}
> |>> d
> {1: 'b'}
> |>> d = {'a': 1, 'b': 1}
> |>> d
> {'a': 1, 'b': 1}
>
> So, if you're running a mathematical function on a range of input (x's)
> and storing the results (y's) as values in a dict, then you *do* want
> the x's to be the keys and the y's to be the values.
>
> I'm guessing that's what you're doing, and if so, you're doing it
> correctly.
>
>   
[this is what i want but am not sure its correct]
> So,  given a dict and an exvalue, how to return the key corresponding
> to the value that's closest to exvalue?
>
> here goes...
>
>   


thanks simon for this, it seems a little easier to understand for me but 
i still get the error when i run the script:

#here is a sample dictionary from the 1000 key:values normally in it. 
they are all non zero and values to 15 decimal places

CDSitdict = {32.030822391220937: "'1.3679999999999874'", 
29.150765445901769: "'2.2079999999999727'", 27.930109636681877: 
"'2.744999999999993'", 28.590095427450688: "'2.4359999999999813'", 
27.595161357952588: "'2.9219999999999997'", 29.961761413410386: 
"'1.9229999999999674'", 36.311798000222424: "'0.66300000000000048'", 
34.358611987430052: "'0.93300000000000072'", 41.199188199569292: 
"'0.20400000000000013'", 29.560651138651014: "'2.057999999999967'"}


#i have tried to format the numerical key into the dictionary to give a 
string using %s but it didnt work so eventually i used
#
#itera = "\'" + `DSit` + "\'"
#CDSitdict[Cpcmax] = itera
#
#i am now wondering if i have been trying to iterate through the key 
value pairs, does the numerical part im trying to iterate over have to 
be the value #side or can it be any side?

#here is a sample exvalue Cpcb = 33.94
**************************************************
def pcloop(dictionary, exvalue):
'''
Return the key in dictionary whose value is
closest to exvalue.

If dictionary is empty, return None.
'''

# Get a iterator over *both* keys and values.
diter = dictionary.iteritems()

# Get the first (key, value) pair.
try:
u, z = diter.next()

except StopIteration:
# The dictionary was empty!
# You might want to do something else here
return

# Compute the closeness of the first value.
closest = abs(z - exvalue)

# Create a var to store the closest key
result = u

# Iterate through the rest of the dict.
for u, z in diter:

# Compute the closeness.
v = abs(z - exvalue)

# Check if it's closer than the closest.
if v < closest:

# If so, store the new closest.
closest = v

# And store the new closest key.
result = u

return result

Cpcb = input("\n\nPlease enter the carbon percentage value obtained from 
the microanalysis. If none, enter 0: ")
print"\n\nCellulose Carbon Percentage is " + `Cpca` + "\n\nMaximum 
potential monomer carbon weight is " + `Cwmax` + "\n\nMaximum potential 
carbon percentage is " + `Cpcmax` + "\n\nPercentage difference between 
Cellulose and Maximum is " + `Cdiff` + "\n\n"
exvalue = Cpcb
dictionary = CDSitdict
CDS = pcloop(dictionary, exvalue)

****************************************
error is:


Traceback (most recent call last):
File "elementalDS.py", line 184, in ?
CDS = pcloop(dictionary, exvalue)
File "elementalDS.py", line 158, in pcloop
closest = abs(z - exvalue)
TypeError: unsupported operand type(s) for -: 'str' and 'float'


:(


ali

-- 
Dr. Alistair King
Research Chemist,
Laboratory of Organic Chemistry,
Department of Chemistry,
Faculty of Science
P.O. Box 55 (A.I. Virtasen aukio 1)
FIN-00014 University of Helsinki
Tel. +358 9 191 50429, Mobile +358 (0)50 5279446
Fax +358 9 191 50366 




More information about the Python-list mailing list