Dictionary Mapping🗺️

The if-elif-elif-elif💥.... chain⛓️

Imagine we were writing code to see the date in a particular format for different countries. So, the starter code looks like this:

from datetime import datetime
today = datetime.now()
cc = input("Enter your country code: ")

if cc == "US": # USA
    print(today.strftime("%m-%d-%y"))
elif cc == "UK": # UK
    print(today.strftime("%d-%m-%y"))
elif cc == "IN": # India
    print(today.strftime("%d-%m-%y"))
else:
    print("No country selected")

This looks relatively harmless, but imagine I want to include all the countries in the world🌏 here. The code becomes unreadable. So, enter dictionary mapping

Dictionary mapping

from datetime import datetime
today = datetime.now()
cc = input("Enter your country code: ")

# Define functions for each country
def us():
    return today.strftime("%m-%d-%y")

def uk():
    return today.strftime("%d-%m-%y")

def india():
    return today.strftime("%d-%m-%y")

def default():
    return "No country selected"

# Create dictionary mapping for each country
countries = {
    "us": us,
    "uk": uk,
    "in": india,
}

print(countries.get(cc, default)())

Dictionary mapping advantages

This code is better (even if it is longer) because of 2 reasons

  1. Each country has its own function. So, the work is distributable to a large team🧑🏻‍🤝‍🧑🏻 (Ex: each person🙍🏻 in the team has to write 10 functions). Its not distributable in the if-elif-else style
  2. Dictionary mapping is faster⚡. We expect the code block to be huge. There are 195 countries in the world (not counting all the countries created in Minecraft and Age of Empires)

    In a if-elif-else style code, the code takes longer to reach the last elif condition because it has to check the conditions of all the elifs sitting on top of it. But dictionary rely on a concept called hashing, which makes search must faster (hashing also used in sets)

Enter LAMBDA

Here comes the application of Lambda. Since each function is only a single line, we can write the functions like this

# Before
def us():
    return today.strftime("%m-%d-%y")
def uk():
    return today.strftime("%d-%m-%y")
def india():
    return today.strftime("%d-%m-%y")
def default():
    return "No country selected"

# After
us = lambda: today.strftime("%m-%d-%y")
uk = lambda: today.strftime("%d-%m-%y")
india = lambda: today.strftime("%d-%m-%y")
default = lambda: "No country selected"

While lambda can be used as an anonymous🥸 function, it can be use with a name as well

As said, it is an anonymous🥸 function. So, why create separate functions with names. We could simply give in dictionary mapping. So, the final code becomes:

from datetime import datetime
today = datetime.now()
cc = input("Enter your country code: ")

# Create default function
default = lambda: "No country selected"

# Create dictionary mapping for each country
countries = {
    "us": lambda: today.strftime("%m-%d-%y"),
    "uk": lambda: today.strftime("%d-%m-%y"),
    "in": lambda: today.strftime("%d-%m-%y"),
}

print(countries.get(cc, default)())

Note: Here the complexity of code maintenance is back i.e., if it were as individual functions it would have been easier to develop by individual contributors. So, we can choose not to do this step. But the performance boost remains because we are still using dictionary mapping

So, that was how lambda + dictionary mapping is used to write optimized code. What other optimizations have you written😉