Click here to Skip to main content
Click here to Skip to main content

Personal Agility - Thinking Outside Your Own Box

By , 22 May 2010
Rate this:
Please Sign up or sign in to vote.

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)

About the Author

John Simmons / outlaw programmer
Software Developer (Senior)
United States United States
I've been paid as a programmer since 1982 with experience in Pascal, and C++ (both self-taught), and began writing Windows programs in 1991 using Visual C++ and MFC. In the 2nd half of 2007, I started writing C# Windows Forms and ASP.Net applications, and have since done WPF, Silverlight, WCF, web services, and Windows services.
 
My weakest point is that my moments of clarity are too brief to hold a meaningful conversation that requires more than 30 seconds to complete. Thankfully, grunts of agreement are all that is required to conduct most discussions without committing to any particular belief system.

Comments and Discussions

 
GeneralWell, it wasn't really an article (not quite long enough), s... PinmvpJohn Simmons / outlaw programmer8-Sep-10 0:02 
GeneralReason for my vote of 3 Interesting article however I am not... PinmemberNeil Searle7-Sep-10 23:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140415.2 | Last Updated 22 May 2010
Article Copyright 2010 by John Simmons / outlaw programmer
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid