1

Let's say I have a list of aliases tied to 5 digit codes available at runtime:

aliasPairs = [(12345,'bob'),(23456,'jon'),(34567,'jack'),(45678,'jill'),(89012,'steph')]

I want to find a terse way to express: replace the id in the line with the matching alias, e.g. :

line = "hey there 12345!"
line = re.sub('\d{5}', value in the aliasPairs which matches the ID, line)
print line

Should output:

hey there bob!

How do Python pros write enumerative expressions in a terse manner?

Thanks and cheers!

Rice
  • 3,371
  • 4
  • 19
  • 23
  • 1
    So each five digit code corresponds to one alias? Consider using a dictionary. – Kevin Aug 07 '18 at 18:47
  • @Kevin that would also do, however an extensible data structure doesn't really matter too much because I will only have a max of about 10-15 aliases hard coded. I am more wondering how to do lambdas and the like in Python. – Rice Aug 07 '18 at 18:50
  • 1
    Python doesn't have a built-in function for lookups in an association list, which is why you want a dictionary. `dict(aliasPairs)` will build the dictionary for you. – chepner Aug 07 '18 at 18:51

2 Answers2

4

Consider using a dictionary when you have a one-to-one mapping of two categories of data, such as five digit codes and aliases. Then it's easy to access any particular alias, given its code:

import re

aliases = {
    "12345":"bob",
    "23456":"jon",
    "34567":"jack",
    "45678":"jill",
    "89012":"steph"
}

line = "hey there 12345!"
line = re.sub('\d{5}', lambda v: aliases[v.group()], line)
print(line)

Result:

hey there bob!
Kevin
  • 74,910
  • 12
  • 133
  • 166
1

If you will be using these aliases directly in your code (not just referenced from data structures) then an Enum is a good way to go1:

from enum import Enum

class Alias(Enum):
    bob = 12345
    jon = 23456
    jack = 34567
    jill = 45678
    steph = 89012

Then using re would look like:

line = "hey there 12345!"
line = re.sub('\d{5}', lambda v: Alias(int(v.group()).name, line)

You could also add that behavior directly to the Alias Enum with a method:

    @classmethod
    def sub(cls, line):
        return re.sub('\d{5}', lambda v: cls(int(v.group())).name, line)

and in use:

Alias.sub("hey there 12345!")

Of course, "bob" should probably be capitalized, but who wants Alias.Bob all over their code? Best to have the substitution text be separate from the Enum member name, a job more easily accomplished with aenum2:

from aenum import Enum
import re

class Alias(Enum):
    _init_ = 'value text'
    bob = 12345, 'Bob'
    jon = 23456, 'Jon'
    jack = 34567, 'Jack'
    jill = 45678, 'Jill'
    steph = 89012, 'Steph'
    @classmethod
    def sub(cls, line):
        return re.sub('\d{5}', lambda v: cls(int(v.group())).text, line)

Alias.sub('hey there 34567!')

1 See this answer for the standard Enum usage.

2 Disclosure: I am the author of the Python stdlib Enum, the enum34 backport, and the Advanced Enumeration (aenum) library.

Ethan Furman
  • 63,992
  • 20
  • 159
  • 237
  • This is a really cool use of the of Enums. Question: the Alias.sub call looks kind of like a static access call to the class Alias, does the _init_ get called the first time I call the Alias.sub method or upon invocation with every call to the 'class'? – Rice Aug 07 '18 at 21:01
  • @Rice: In `Enum` classes all the `Enum` members (aka class instances) are created when the class itself is created; both `__new__` and `__init__` are invoked at that time. Any future operations that return an `Enum` member are returning one of the already created members. – Ethan Furman Aug 08 '18 at 02:58