Simon Forman wrote: > [EMAIL PROTECTED] 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 -- http://mail.python.org/mailman/listinfo/python-list