views:

4017

answers:

7

What's the fastest and easiest to read implementation of calculating the sum of digits?

I.e. Given the number: 17463 = 1 + 7 + 4 + 6 + 3 = 21

+25  A: 

You could do it arithmetically, without using a string:

sum = 0;
while (n != 0) {
    sum += n % 10;
    n /= 10;
}
Greg Hewgill
Beat me to it. This is the best way.
Simucal
Personally, I see this better conceptually as a for loop... But maybe that's just my mind, I tend to see everything better as a for loop...
Matthew Scharley
@monoxide, the while loop is more succinct. You have no need for an index or for tight control of the loop iterations.
Simucal
for (; n!= 0; n /= 10) { sum += n % 10;} To my mind there's an implicit counter there, n. But my mind is known to work funilly when talking about loops. There's no need to initialise n of course, because that's handled before the loop presumably.
Matthew Scharley
+4  A: 
 public static int SumDigits(int value)
 {
     int sum = 0;
     while (value != 0)
     {
         int rem;
         value = Math.DivRem(value, 10, out rem);
         sum += rem;
     }
     return sum;
 }
Jon Skeet
Assuming DivRem does the intelligent thing, this should avoid doing the division twice. I like it better than the other obvious answer (though both are close).
Software Monkey
This is the code of DivRempublic static int DivRem(int a, int b, out int result){ result = a % b; return (a / b);} so it does not make intelligent thing!!
Ahmed Said
Any reasonable compiler will see that x and y don't change between the x/y and x%y operations and thus can utilize a single divsion op to get both results. I know that gcc does this for c/c++ code. I assume c# compilers are at least as competent with such a simple optimization.
Evan Teran
This almost certainly isn't something the C# compiler would do - it would be up to the JIT.
Jon Skeet
fair enough, I was kinda lumping the JIT and the compiler proper into one category, but yea, the JIT would do the actual optimization.
Evan Teran
+8  A: 

I use

int result = 17463.ToString().Sum(c => c - '0');

It uses only 1 line of code.

chaowman
Converting an integer to a string in order to sum it's values is not really very efficient. I also don't consider this code especially readable. Though I didn't downvote this.
Brian
You forgot to convert the string to array first.17463.ToString().ToCharArray().Sum(c => c - '0');
Hasan Khan
You don't have to convert it to an array first.
atsjoo
+1 from me, I like oneliners.. :)
Stefan
Very nice and functional approach!
Martijn
A: 

I like the chaowman's response, but would do one change

int result = 17463.ToString().Sum(c => Convert.ToInt32(c));

I'm not even sure the c - '0', syntax would work? (substracting two characters should give a character as a result I think?)

I think it's the most readable version (using of the word sum in combination with the lambda expression showing that you'll do it for every char). But indeed, I don't think it will be the fastest.

Tjipke
+7  A: 

For integer numbers, Greg Hewgill has most of the answer, but forgets to account for the n < 0. The sum of the digits of -1234 should still be 10, not -10.

n = Math.Abs(n);
sum = 0;
while (n != 0) {
    sum += n % 10;
    n /= 10;
}

It the number is a floating point number, a different approach should be taken, and chaowman's solution will completely fail when it hits the decimal point.

Ants
Good catch. It all depends on how the modulo operator is defined in the language in question; in C# the result takes the same sign as the dividend which makes my method fail for negative numbers. In other languages it may work, see the table at http://en.wikipedia.org/wiki/Modulo_operation
Greg Hewgill
+5  A: 
int num = 12346;
int sum = 0;
for (int n = num; n > 0; sum += n % 10, n /= 10) ;
Hasan Khan
+1  A: 

I would suggest that the easiest to read implementation would be something like:

public int sum(int number)
{
    int ret = 0;
    foreach (char c in Math.Abs(number).ToString())
        ret += c - '0';
    return ret;
}

This works, and is quite easy to read. BTW: Convert.ToInt32('3') gives 51, not 3. Convert.ToInt32('3' - '0') gives 3.

I would assume that the fastest implementation is Greg Hewgill's arithmetric solution.

sindre j