Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / programming

Personal Agility - Thinking Outside Your Own Box

4.60/5 (3 votes)
22 May 2010CPOL4 min read 10.8K  
Essential programmer skill - the ability to approach a problem from more that one direction.

How This Tip Was Born


A homework question was recently posted in the C# forum (the following is a paraphrased version):

"Given an integer (assumed to be Int32) value, extract the individual digits using mathematical functions."

Now, everyone (including me) balked at the idea of doing it this way since converting it to a string object would have been more convenient, and proceeded to provide string-based answers. After all, why not use the tools provided by the framework? After a day or so, the question popped up again (by someone else) in Quick Answers, and I started to view this as a personal challenge to come up with an answer.

My initial solution was to perform math on the original value in such a way as to extract the digits starting at the right side of the number and moving to the left side.

List<int> digits = new List<int>();
int counter = 0;
double power = 0;
while (value != 0)
{
    counter++;
    power = Math.Pow(10d, 1);
    digits.Add(value % (int)power);
    value = (int)((double)value / power);
}
digits.Reverse();

Fine and dandy, and it worked great. However, as most of us know, requirements for a given task often change just as we deliver our gleaming code jewel that's perfect in every way, and this particular task is no exception. Bill Woodruff suggested the following additional (and more stringent) requirements to create a more interesting problem:

1. The integer value can be in the range int.MinValue to int.MaxValue : you can make no assumptions about the range of those values a priori

2. You cannot use try/catch or any other "error handling" method to "work around" an overflow error.

3. If the integer value < 0, the first digit must also be negative.

4. Your function :

&nbsp;&nbsp;&nbsp;&nbsp;a. Must take the integer value as its sole parameter

&nbsp;&nbsp;&nbsp;&nbsp;b. Can return your choice of List<int> or int[]

5. Can have no single loop (of any type) that iterates more times than the maximum power to which 10 can be raised which exceeds the integer value input.

My original code already met requirements #1, #2, #4, and #5, so here's what I came up with:

public static List<int> ExtractDigits(int value)
{
    List<int> digits = new List<int>();
    int counter = 0;
    double power = 0;
    while (value != 0)
    {
        counter++;
        power = Math.Pow(10d, 1);
        // if we only want the left-most digit to be negativem, we have to 
        // check the value to see if it's less than -10, and then multiply 
        // it by the appropriately signed value of 1
        digits.Add((value % (int)power) * ((value < -10) ? -1 : 1));
        value = (int)((double)value / power);
    }
    digits.Reverse();
    return digits;
}

I was pretty happy with myself, and then Rod Kemp suggested being able to extract the digits starting with the left-most digit. Back to work!

public static List<int> ExtractDigits2(int value)
{
    bool isNegative = (value < 0);
    double i = 9;
    double power = 0;
    List<int> digits = new List<int>();
    while (value != 0)
    {
        power = Math.Pow(10d, i);
        int result = (value - (value % (int)power));
        // this time, the negative number is the first one we'll be extracting, 
        // so we have to modify our multiplier code a bit.
        int addResult = (int)((double)result / power) * ((isNegative && (int)i == 9) ? 1 : -1);
        digits.Add(addResult);
        value -= result;
        i--;
    }
    return digits;
}

Now, some of you will notice (and Bill certainly did) that I assumed that the value being passed in was an Int32 (what an int type currently translates to), and the variable i is set to the power of ten represented by int.MaxValue. While he is right that it's possible to find the actual maximum power value, I view that as unnecessary code (it involves running through a loop to find the value), and the obvious - and IMHO the best - solution is to create method overloads for each of the integer types. This would save us an admittedly minuscule amount of time by not having to traverse a small loop, but any performance gains we can reasonably accomplish without too severe an impact on the code are positive and worth doing. So changing the types in the method above to Int32 (and providing overloads for the other integer types) would address his "no prior knowledge" requirement.

Where's The Tip


So here we are, and you're probably wondering, "What the Hell is he on about?" The whole point of this tip is to illustrate that it's absolutely necessary to develop and build on an ability to think on your feet, to attack a problem until it's solved, and to be able to change direction at a moment's notice. Yes, at times it will be distasteful. Yes, at times the requirements may seem to be just too bizarre for words. Yes, at times you'll have to throw away what seems like mountains of otherwise good code in order to meet the stated requirements. Yes, it might make you think a little harder about a problem. But at the same time, you will foster a subconscious desire to do so at the outset of a task, and your code will reflect it.

From a casual observer's standpoint, it will appear that your code is rigid and inflexible, but there lies the rub. It isn't. You see it for what it is - a foundation for better ideas, and (sometimes wildly) different requirements. And it is. Why? Because not only did you think outside the box to get your answer, but you expanded your own box as a result, and you can see the possibilities that your code empowers.



License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)