DEV Community

Cover image for Way Too Many IF-THEN-ELSEs?  Try a Lookup Table
Bill Costa
Bill Costa

Posted on

Way Too Many IF-THEN-ELSEs? Try a Lookup Table

This article illustrates a use case where a simple-to-implement lookup table can be used as a better alternative to hard coding decision logic. The coding trick used here should be applicable to any programming language with multi-dimensional associative arrays.

When would you want to do this?

A problem I've faced more than a few times is having a set of variables, perhaps aggregating data from various sources, and needing to determine what overall state, from a limited set of valid states, is being represented by those values. My first cut at the problem would probably be to draw a decision tree, considering each variable in turn, and then try to implement that tree's logic using nested if-then-else and/or case (switch) statements. Depending upon the scope and nature of the problem, this could result in a lot of logic that may be hard to follow, debug, or extend.

One possible alternative is to create a lookup table that enumerates all the expected values for each variable, and to assign the desired state represented by each row of that table. Creating the table may be a bit tedious, but it can be more easily understood by non-coders, and the logic for doing the lookup can be near trivial. And perhaps the biggest win is the simplicity in adding, removing, and modifying states by updating the table, rather than hacking on the logic.

Let's consider a simple example; ordering a car where there are five different trim lines and a set of options. Not all options are available for all trim lines. Here's what that might look like:

Trim Interior Wheels Transmission Cruise
Base cloth steel | alloy manual n/a
Premium cloth | leather alloy manual | auto n/a
Sport sport-cloth 18" black alloy 6 speed manual opt
Limited cloth | leather alloy manual | auto std
Touring leather 18" alloy auto std

We've been tasked to write a function that determines if a set of dealer selected options are allowed for a given trim line, and to identify a valid combination of options and trim as a particular 'bundle' identifier. Our first step will be to expand the table so that all possible valid combinations are enumerated, and we'll simplify the identifiers a bit.

Trim Interior Wheels Transmission Cruise Bundle
Base cloth steel manual 0 B1
Base cloth alloy manual 0 B2
Premium cloth alloy manual 0 P1
Premium leather alloy manual 0 P2
Premium cloth alloy auto 0 P3
Premium leather alloy auto 0 P4
Sport sport sport sport 0 S1
Sport sport sport sport 1 S2
Limited cloth alloy manual 1 L1
Limited leather alloy manual 1 L2
Limited cloth alloy auto 1 L3
Limited leather alloy auto 1 L4
Touring leather touring auto 1 T1

When we are convinced that we have enumerated all of the valid possible combinations, we can turn this table into a multi-dimensional hash. The resulting Perl code, shown below, bears an uncanny resemblance to our table.

%bundle = ();
#       Trim      Interior  Wheels    Trannie  Cruise Bundle
#       --------- --------- --------- -------- ------ ------
$bundle {base}    {cloth}   {steel}   {manual} {0}   = 'B1';
$bundle {base}    {cloth}   {alloy}   {manual} {0}   = 'B2';
$bundle {premium} {cloth}   {alloy}   {manual} {0}   = 'P1';
$bundle {premium} {leather} {alloy}   {manual} {0}   = 'P2';
$bundle {premium} {cloth}   {alloy}   {auto}   {0}   = 'P3';
$bundle {premium} {leather} {alloy}   {auto}   {0}   = 'P4';
$bundle {sport}   {sport}   {sport}   {sport}  {0}   = 'S1';
$bundle {sport}   {sport}   {sport}   {sport}  {1}   = 'S2';
$bundle {limited} {cloth}   {alloy}   {manual} {1}   = 'L1';
$bundle {limited} {leather} {alloy}   {manual} {1}   = 'L2';
$bundle {limited} {cloth}   {alloy}   {auto}   {1}   = 'L3';
$bundle {limited} {leather} {alloy}   {auto}   {1}   = 'L4';
$bundle {touring} {leather} {touring} {auto}   {1}   = 'T1';
Enter fullscreen mode Exit fullscreen mode

Now to determine if we have been given a valid combination of trim and options, and to return the bundle code, we just do:

$trim   = 'touring';
$seats  = 'leather';
$wheels = 'touring';
$trans  = 'auto';
$cruise = 1;

$bCode = $bundle{$trim}{$seats}{$wheels}{$trans}{$cruise};
Enter fullscreen mode Exit fullscreen mode

If $bCode is defined, then we know the combination is valid and we have our bundle code (T1).

Notice how adding a new trim line or a new option is just a matter of modifying the table with little or no change to the lookup statement. In contrast, a block of if-then-elsif statements might not be so easy to hack and debug.

An interactive command-line demo script, which also includes error handling and validation, can be found here.

Top comments (5)

Collapse
 
mjgardner profile image
Mark Gardner

Watch out for autovivication.

Collapse
 
billcosta profile image
Bill Costa

You bet! I glossed over that in the code example in this article because I wanted the code to be as clear as possible for non-Perl folks. I'm hoping that people who are interested in the Perl aspect will take the time to look at the demo. It uses exists() instead of defined() when testing against the table for just that reason. In the demo I also wanted to avoid dependancies. But at some point I would like to circle back and explore if the lookup table can be made read-only after it is built, which would be better still. I just need to take the time to explore modules like ReadonlyX.

Collapse
 
grinnz profile image
Dan • Edited

ReadonlyX is a great option for this. Note that exists and defined both still autovivify any intermediate structures - e.g. if you are looking at $foo->{bar}{baz} then $foo will be autovivified to {bar => {}} regardless of what the end check is (the final element will not be vivified unless assigned to). Two options for avoiding this are autovivification and my Data::DeepAccess.

Collapse
 
saulburgos profile image
Saul Burgos Davila

Very interesing, What would it be the equivalent in Javascript?

Collapse
 
billcosta profile image
Bill Costa

It looks like you might use a Javascript object rather than an associative array to build the table with a similar easy to read syntax. Check out this stack overflow question. Beyond that I can't say since I don't have Javascript in my tool belt yet. (On my todo list.)