help - iter & dict

A

aking

Dear Python people,

im a newbie to python and here...so hello!

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
 
J

Justin Azoff

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: [snip]
short time. I was trying to define a function (its my first!) so that i
could apply to several 'dictionary's and 'exvalue's.
[snip]

If you plan on searching a single dictionary for many values, it may be
much faster to convert the dictionary into a sorted list, and use the
bisect module to find the closest value...

something like:

import bisect

class closer_finder:
def __init__(self, dataset):
self.dataset = dataset
flat = [(k,v) for v,k in dataset.iteritems()]
flat.sort()
self.flat = flat

def __getitem__(self, target):
flat = self.flat
index = bisect.bisect_right(flat, (target, ))

#simple cases, smaller than the smaller,
#or larger than the largest
if index == 0:
v,k = flat[0]
return k,v
elif index == len(flat):
v,k = flat[-1]
return k,v

#otherwise see which of the neighbors is closest.
leftval, leftkey = flat[index-1]
rightval, rightkey = flat[index]

leftdiff = abs(leftval - target)
rightdiff = abs(rightval - target)

if leftdiff <= rightdiff:
return leftkey, leftval
else:
return rightkey, rightval

In [158]:sample_data
Out[158]:{'a': 1, 'c': 6, 'b': 3}

In [159]:d=closer_finder(sample_data)

In [160]:d.flat
Out[160]:[(1, 'a'), (3, 'b'), (6, 'c')]

In [161]:d[4]
Out[161]:('b', 3)
 
S

Simon Forman

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.

|>> d = {}
|>> d.get
<built-in method get of dict object at 0xb7dd43e4>
|>> d.get[23]
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: unsubscriptable object

So you want to use ()'s, not []'s.

Further, get() works with *keys*, not *values*. If you call it with a
value, it won't work, instead it will return None. Unless, of course,
you *have* a key with the same value as your value, in which case it
will return the value associated with the key, but NOT the key
associated with the value (that you passed to get().)

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.

Let me address one last problem in your code above and then I'll show
you a neat way to return the key whose associated value is closest to
some value exvalue.


In this part of your code,
if v < 0.001:
u = dictionary.get[z]
return u

the return statement should be at the same indentation level as the
assignment statement:

if v < 0.001:
u = dictionary.get[z] # <- note, this won't work
return u

or even just

if v < 0.001:
return dictionary.get[z] # <- note, this won't work

The way you have it now, the return statement would execute immediately
after the if statement, regardless of whether v < 0.001 or not. Not
too bad if the very first value was close enough to exvalue. But if it
wasn't, 'u' would not have been defined by the time the return
statement tried to return it, and you would have gotten a NameError.
You probably already know this, and the indentation error was just a
minor typo.


So, given a dict and an exvalue, how to return the key corresponding
to the value that's closest to exvalue?

here goes...


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


I hope that helps. :)

Python is an amazing language once you get the hang of it. Enjoy.


Peace,
~Simon
 
A

Alistair King

Simon said:
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,143
Latest member
SterlingLa
Top