[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.python

different key, same value in dictionaries

Magdoll

2/9/2008 9:52:00 PM

Is there a cleaner way to do this example:

d = {('a','b'): 10, ('a','c'): 20, ('b','c'): 30}

The key is always a pair (x,y), but d[(x,y)] should have the same
result as d[(y,x)]. So either I would have to store both d[(x,y)] and
d[(y,x)] (unncessary extra space?), or write something like:

if x <= y: return d[(x,y)]
else: return d[(y,x)]

I'm not familiar with python enough, so I want to know whether these
are my only choices....
4 Answers

Steven D'Aprano

2/9/2008 10:21:00 PM

0

On Sat, 09 Feb 2008 13:51:34 -0800, Magdoll wrote:

> Is there a cleaner way to do this example:
>
> d = {('a','b'): 10, ('a','c'): 20, ('b','c'): 30}
>
> The key is always a pair (x,y), but d[(x,y)] should have the same result
> as d[(y,x)]. So either I would have to store both d[(x,y)] and d[(y,x)]
> (unncessary extra space?)

Worse than the extra space is the near certainty of d[(x,y)] and d[(y,x)]
getting out of sync.


> or write something like:
>
> if x <= y: return d[(x,y)]
> else: return d[(y,x)]

Arggh, scattering all those tests throughout your code is too much like
hard work!


> I'm not familiar with python enough, so I want to know whether these are
> my only choices....

Oh no. Here's a good one:


class PairDict(dict):
def __getitem__(self, key):
if key[1] < key[0]: key = (key[1], key[0])
return super(PairDict, self).__getitem__(key)


and here it is in use:

>>> d = PairDict([((1,2), 5), ((3,4), 10)])
>>> d[(1,2)]
5
>>> d[(2,1)]
5



--
Steven

Gary Herron

2/9/2008 11:33:00 PM

0

Magdoll wrote:
> Is there a cleaner way to do this example:
>
> d = {('a','b'): 10, ('a','c'): 20, ('b','c'): 30}
>
> The key is always a pair (x,y), but d[(x,y)] should have the same
> result as d[(y,x)]. So either I would have to store both d[(x,y)] and
> d[(y,x)] (unncessary extra space?), or write something like:
>
> if x <= y: return d[(x,y)]
> else: return d[(y,x)]
>
> I'm not familiar with python enough, so I want to know whether these
> are my only choices....
>
You could use ImmutableSets as indexes. (In fact this is the whole
reason for the existence of ImmutableSets.)

You could derive your own dictionary type from the builtin dictionary
type, and map an index operation d[(x,y)] to
d[ImmutableSet(a,b)]. Then all of d[a,b], d[b,a], d[(a,b)] and d[(b,a)]
would index the same element.

See http://docs.python.org/lib/module... for details of the set
module.

Gary Herron

Matt Nordhoff

2/9/2008 11:46:00 PM

0

Gary Herron wrote:
> You could use ImmutableSets as indexes. (In fact this is the whole
> reason for the existence of ImmutableSets.)
>
> You could derive your own dictionary type from the builtin dictionary
> type, and map an index operation d[(x,y)] to
> d[ImmutableSet(a,b)]. Then all of d[a,b], d[b,a], d[(a,b)] and d[(b,a)]
> would index the same element.
>
> See http://docs.python.org/lib/module... for details of the set
> module.

Since Python 2.4, sets are built-in types. Use "set" and "frozenset"
instead of "sets.Set" and "sets.ImmutableSet", respectively.

If you need Python 2.3 compatibility, you can do something like this:

try:
set, frozenset
except NameError:
from sets import Set as set, ImmutableSet as frozenset
--

Paul Rubin

2/10/2008 12:51:00 AM

0

Matt Nordhoff <mnordhoff@mattnordhoff.com> writes:
> Since Python 2.4, sets are built-in types. Use "set" and "frozenset"
> instead of "sets.Set" and "sets.ImmutableSet", respectively.
>
> If you need Python 2.3 compatibility, you can do something like this:

As an alternative, you could canonicalize the keys by sorting them
into lexicographic order. I.e. you'd store both (2,3) and (3,2) as
(2,3).