Subscribe to MentalFloss Minutes        RSS Feed
-----

Big IF Or List?

Icon 1 Comments
Let's create a contrived example where the user has selected from an assortment of food. If the user selects a fruit, we want to say "Don't forget to eat your vegetables.", and if they select a vegetable, we'll say "Remember, an apple a day keeps the doctor away."

We might have some such enumeration:

typedef enum {
	APPLE,
	PEAR,
	PEACH,
	BANANA,
	CARROT,
	LETTUCE,
	RADISH,
	BROCCOLI,
	POTATO
} Food;



We see that the fruits are: APPLE, PEAR, PEACH, BANANA.
The vegetables are: CARROT, LETTUCE, RADISH, BROCCOLI, POTATO

We might be tempted to write something like this:

int main()
{
	Food food = APPLE;

	if(food == APPLE || food == PEAR || food == PEACH || food == BANANA)
	{
		cout << "Don't forget to eat your vegetables." << endl;
	}
	else if(food == CARROT || food == LETTUCE || food == RADISH || food == BROCCOLI || food == POTATO)
	{
		cout << "Remember, an apple a day keeps the doctor away." << endl;
	}
	else
	{
		cout << "Please eat something." << endl;
	}

	return 0;
}



But look at those if checks. We might instead want to create a collection and search through it via the find() function in algorithm. We specify the begin, end, and search item, and ensure that it is not at the end of the list.

#include <iostream>
#include <algorithm>

using namespace std;

typedef enum {
	APPLE,
	PEAR,
	PEACH,
	BANANA,
	CARROT,
	LETTUCE,
	RADISH,
	BROCCOLI,
	POTATO
} Food;

int main()
{
	Food fruits[] = { APPLE, PEAR, PEACH, BANANA };
	Food vegetables[] = { CARROT, LETTUCE, RADISH, BROCCOLI, POTATO };

	Food food = APPLE;

	if(find(begin(fruits), end(fruits), food) != end(fruits))
	{
		cout << "Don't forget to eat your vegetables." << endl;
	}
	else if(find(begin(vegetables), end(vegetables), food) != end(vegetables))
	{
		cout << "Remember, an apple a day keeps the doctor away." << endl;
	}
	else
	{
		cout << "Please eat something." << endl;
	}

	return 0;
}



And now we've avoided long if statements at the expense of a little extra required space.

Unfortunately, we cannot exactly generalize this into a function without converting to vectors.

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

typedef enum {
	APPLE,
	PEAR,
	PEACH,
	BANANA,
	CARROT,
	LETTUCE,
	RADISH,
	BROCCOLI,
	POTATO,
	NONE
} Food;

bool is_type(vector<Food> list, Food food)
{
	return find(list.begin(), list.end(), food) != list.end();
}

int main()
{
	vector<Food> fruits = { APPLE, PEAR, PEACH, BANANA };
	vector<Food> vegetables = { CARROT, LETTUCE, RADISH, BROCCOLI, POTATO };

	Food food = RADISH;

	if(is_type(fruits, food))
	{
		cout << "Don't forget to eat your vegetables." << endl;
	}
	else if(is_type(vegetables, food))
	{
		cout << "Remember, an apple a day keeps the doctor away." << endl;
	}
	else
	{
		cout << "Please eat something." << endl;
	}

	return 0;
}



And since our lists aren't going to have duplicates, let's make this a set instead.

#include <iostream>
#include <set>
#include <algorithm>

using namespace std;

typedef enum {
	APPLE,
	PEAR,
	PEACH,
	BANANA,
	CARROT,
	LETTUCE,
	RADISH,
	BROCCOLI,
	POTATO,
	NONE
} Food;

bool is_type(set<Food> list, Food food)
{
	return find(list.begin(), list.end(), food) != list.end();
}

int main()
{
	set<Food> fruits = { APPLE, PEAR, PEACH, BANANA };
	set<Food> vegetables = { CARROT, LETTUCE, RADISH, BROCCOLI, POTATO };

	Food food = RADISH;

	if(is_type(fruits, food))
	{
		cout << "Don't forget to eat your vegetables." << endl;
	}
	else if(is_type(vegetables, food))
	{
		cout << "Remember, an apple a day keeps the doctor away." << endl;
	}
	else
	{
		cout << "Please eat something." << endl;
	}

	return 0;
}



Now, we might be more interested in the readability, and scope of these lists. So, instead we might create functions specific to the question, and maintain constant lists.

#include <iostream>
#include <set>
#include <algorithm>

using namespace std;

typedef enum {
	APPLE,
	PEAR,
	PEACH,
	BANANA,
	CARROT,
	LETTUCE,
	RADISH,
	BROCCOLI,
	POTATO,
	NONE
} Food;

static const set<Food> fruits = { APPLE, PEAR, PEACH, BANANA };
static const set<Food> vegetables = { CARROT, LETTUCE, RADISH, BROCCOLI, POTATO };

bool is_type(set<Food> list, Food food)
{
	return find(list.begin(), list.end(), food) != list.end();
}

bool is_fruit(Food food)
{
	return is_type(fruits, food);
}

bool is_vegetable(Food food)
{
	return is_type(vegetables, food);
}

int main()
{
	Food food = RADISH;

	if(is_fruit(food))
	{
		cout << "Don't forget to eat your vegetables." << endl;
	}
	else if(is_vegetable(food))
	{
		cout << "Remember, an apple a day keeps the doctor away." << endl;
	}
	else
	{
		cout << "Please eat something." << endl;
	}

	return 0;
}



So, everything's going well, but a feature enhancement has been posted that we now want to allow desserts of COOKIE, PIE, CAKE, and if they select one then print "Watch out for diabetes." How do we change? Well, create new entries in the enum, add a list, create another function, and add another if check.

#include <iostream>
#include <set>
#include <algorithm>

using namespace std;

typedef enum {
	APPLE,
	PEAR,
	PEACH,
	BANANA,
	CARROT,
	LETTUCE,
	RADISH,
	BROCCOLI,
	POTATO,
	COOKIE,
	PIE,
	CAKE,
	NONE
} Food;

static const set<Food> fruits = { APPLE, PEAR, PEACH, BANANA };
static const set<Food> vegetables = { CARROT, LETTUCE, RADISH, BROCCOLI, POTATO };
static const set<Food> desserts = { COOKIE, PIE, CAKE };

bool is_type(set<Food> list, Food food)
{
	return find(list.begin(), list.end(), food) != list.end();
}

bool is_fruit(Food food)
{
	return is_type(fruits, food);
}

bool is_vegetable(Food food)
{
	return is_type(vegetables, food);
}

bool is_dessert(Food food)
{
	return is_type(desserts, food);
}

int main()
{
	Food food = CAKE;

	if(is_fruit(food))
	{
		cout << "Don't forget to eat your vegetables." << endl;
	}
	else if(is_vegetable(food))
	{
		cout << "Remember, an apple a day keeps the doctor away." << endl;
	}
	else if(is_dessert(food))
	{
		cout << "Watch out for diabetes." << endl;
	}
	else
	{
		cout << "Please eat something." << endl;
	}

	return 0;
}



So, we got to this from this (updated with change):


int main()
{
	Food food = APPLE;

	if(food == APPLE || food == PEAR || food == PEACH || food == BANANA)
	{
		cout << "Don't forget to eat your vegetables." << endl;
	}
	else if(food == CARROT || food == LETTUCE || food == RADISH || food == BROCCOLI || food == POTATO)
	{
		cout << "Remember, an apple a day keeps the doctor away." << endl;
	}
    else if(food == COOKIE || food == PIE || food == CAKE)
    {
            cout << "Watch out for diabetes." << endl;
    }
	else
	{
		cout << "Please eat something." << endl;
	}

	return 0;
}



We could create functions for those if statements to be fair.

So, in the end, just a different way to do something that sometimes might be beneficial.

1 Comments On This Entry

Page 1 of 1

modi123_1 

17 October 2018 - 07:10 AM
I like this.

Now add 'tomato' to the list and tell me where that falls. :)

Obligatory:

Posted Image
0
Page 1 of 1

November 2018

S M T W T F S
    123
45678910
11121314151617
18192021 22 2324
252627282930 

Tags

    Recent Entries

    Recent Comments

    Search My Blog

    0 user(s) viewing

    0 Guests
    0 member(s)
    0 anonymous member(s)