rwallace
rwallace

Reputation: 33395

Two-way mapping between strings and integers

Given a collection of pairs of strings and (non-contiguous) integers, which are known in advance, a Python dictionary literal is a straightforward way to define a mapping from either to the other.

But supposing some parts of your program will have a string and want the corresponding integer, and others will have an integer and want the corresponding string, what's the best way to arrange this? Of course I could write out two separate dictionary literals, but that violates DRY, or I could do a bit of hacking with a function that uses globals() to create two dictionary variables from a single set of inputs, but I'm not sure how idiomatic that is. What's the recommended way? (I'm using Python 2.7 if it matters.)

Upvotes: 3

Views: 1072

Answers (3)

abarnert
abarnert

Reputation: 365767

Instead of using a pair of dicts, why not use an enum?

Of course the stdlib enum module requires 3.4, but its source is available to read and backport, or you can get the semi-official backport off PyPI, or any of the dozens of other enum packages.

For example:

>>> import enum
>>> class Color(enum.Enum):
...     red = 1
...     green = 2
...     blue = 3
>>> Color.red
<Color.red: 1>
>>> Color['red']
<Color.red: 1>
>>> Color(1)
<Color.red: 1>
>>> Color(1).name
'red'
>>> Color['red'].value
1

My guess is, most of the time you won't actually be mapping back and forth between these, but just using Color.red, instead of your current "red" or 1, as a value. (If you want to be able to use the value directly as either an int or a str, look at the other classes in the docs.)

There should be good examples all over the 3.4 stdlib of how to convert code that used to use numbers and map them to strings and vice-versa into code that uses Enums instead. Unfortunately, as of 3.4b1, most of those examples haven't been written yet… I believe socket.AddressFamily and a few related types are the only ones that have made it so far. But if you can't figure it out, show an MCVE, and it should be easy to show you how to convert it.

Upvotes: 5

aidnani8
aidnani8

Reputation: 2127

You can use bidict https://pypi.python.org/pypi/bidict to do this.

Upvotes: 5

jonrsharpe
jonrsharpe

Reputation: 122062

You could make the second mapping automatically from the first:

d2 = {v:k for k, v in d1.items()}

Upvotes: 5

Related Questions