count odd and even digits in a number - c#

I try to write program that check the ratio between odd and even
digits in a given number. I've had some problems with this code:
static void Main(string[] args)
{
int countEven = 0 ;
int countOdd = 0 ;
Console.WriteLine("insert a number");
int num = int.Parse(Console.ReadLine());
int length = num.GetLength;
for (int i = 0;i<length ; i++)
{
if((num/10)%2) == 0)
int countEven++;
}
}
any ideas?

The problem is that int does not have a length, only the string representation of it has one.As an alternative to m.rogalski answer, you can treat the input as a string to get all the digits one by one. Once you have a digit, then parsing it to int and checking if it is even or odd is trivial.Would be something like this:
int countEven = 0;
int countOdd = 0;
Console.WriteLine("insert a number");
string inputString = Console.ReadLine();
for (int i = 0; i < inputString.Length; i++)
{
if ((int.Parse(inputString[i].ToString()) % 2) == 0)
countEven++;
else
countOdd++;
}

Linq approach
Console.WriteLine("insert a number");
string num = Console.ReadLine(); // check for valid number here?
int countEven = num.Select(x => x - '0').Count(x => x % 2 == 0);
int countOdd = num.Select(x => x - '0').Count(x => x % 2 != 0);

Let's assume your input is : 123456
Now all you have to do is to get the modulo from the division by ten : int m = num % 10;
After that just check if bool isEven = m % 2 == 0;
On the end you have to just divide your input number by 10 and repeat the whole process till the end of numbers.
int a = 123456, oddCounter = 0, evenCounter = 0;
do
{
int m = a % 10;
switch(m % 2)
{
case 0:
evenCounter++;
break;
default: // case 1:
oddCounter++;
break;
}
//bool isEven = m % 2 == 0;
}while( ( a /= 10 ) != 0 );
Online example

Made a small change to your code and it works perfectly
int countEven = 0;
int countOdd = 0;
Console.WriteLine( "insert a number" );
char[] nums = Console.ReadLine().ToCharArray();
for ( int i = 0; i < nums.Length; i++ )
{
if ( int.Parse( nums[i].ToString() ) % 2 == 0 )
{
countEven++;
}
else
{
countOdd++;
}
}
Console.WriteLine($"{countEven} even numbers \n{countOdd} odd numbers");
Console.ReadKey();
What I do is get each number as a a character in an array char[] and I loop through this array and check if its even or not.

If the Input number is a 32-bit integer (user pick the length of the number)
if asked:
The number of even digits in the input number
Product of odd digits in the input number
The sum of all digits of the input number
private void button1_Click(object sender, EventArgs e) {
int num = ConvertToInt32(textBox1.Text);
int len_num = textBox1.Text.Length;
int[] arn = new int[len_num];
int cEv = 0; pOd = 0; s = 0;
for (int i = len_num-1; i >= 0; i--) { // loop until integer length is got down to 1
arn[i] = broj % 10; //using the mod we put the last digit into a declared array
if (arn[i] % 2 == 0) { // then check, is current digit even or odd
cEv++; // count even digits
} else { // or odd
if (pOd == 0) pOd++; // avoid product with zero
pOd *= arn [i]; // and multiply odd digits
}
num /= 10; // we divide by 10 until it's length is get to 1(len_num-1)
s += arn [i]; // sum of all digits
}
// and at last showing it in labels...
label2.Text = "a) The even digits count is: " + Convert.ToString(cEv);
label3.Text = "b) The product of odd digits is: " + Convert.ToString(pOd);
label4.Text = "c) The sum of all digits in this number is: " + Convert.ToString(s);
}
All we need in the interface is the textbox for entering the number, the button for the tasks, and labels to show obtained results. Of course, we have the same result if we use a classic form for the for loop like for (int i = 0; and <= len_num-1; i++) - because the essence is to count the even or odd digits rather than the sequence of the digits entry into the array

static void Main(string args[]) {
WriteLine("Please enter a number...");
var num = ReadLine();
// Check if input is a number
if (!long.TryParse(num, out _)) {
WriteLine("NaN!");
return;
}
var evenChars = 0;
var oddChars = 0;
// Convert string to char array, rid of any non-numeric characters (e.g.: -)
num.ToCharArray().Where(c => char.IsDigit(c)).ToList().ForEach(c => {
byte.TryParse(c.ToString(), out var b);
if (b % 2 == 0)
evenChars++;
else
oddChars++;
});
// Continue with code
}
EDIT:
You could also do this with a helper (local) function within the method body:
static void Main(string args[]) {
WriteLine("Please enter a number...");
var num = ReadLine();
// Check if input is a number
if (!long.TryParse(num, out _)) {
WriteLine("NaN!");
return;
}
var evenChars = 0;
var oddChars = 0;
// Convert string to char array, rid of any non-numeric characters (e.g.: -)
num.ToCharArray().Where(c => char.IsDigit(c)).ToList().ForEach(c => {
byte.TryParse(c.ToString(), out var b);
if (b % 2 == 0)
evenChars++;
else
oddChars++;
// Alternative method:
IsEven(b) ? evenChars++ : oddChars++;
});
// Continue with code
bool IsEven(byte b) => b % 2 == 0;
}
Why am I using a byte?
Dealing with numbers, it is ideal to use datatypes that don't take up as much RAM.
Granted, not as much an issue nowadays with multiple 100s of gigabytes possible, however, it is something not to be neglected.
An integer takes up 32 bits (4 bytes) of RAM, whereas a byte takes up a single byte (8 bits).
Imagine you're processing 1 mio. single-digit numbers, and assigning them each to integers. You're using 4 MiB of RAM, whereas the byte would only use up 1 MiB for 1 mio. numbers.
And seeming as a single-digit number (as is used in this case) can only go up to 9 (0-9), you're wasting a potential of 28 bits of memory (2^28) - whereas a byte can only go up to 255 (0-255), you're only wasting a measly four bits (2^4) of memory.

Related

c# find if whether the number is happy or not

Im trying to understund how do I find whether the number is Happy Number or not,
I know that i need to check if the unit digit and the digit in the highest number location are greater
then the numbers in the middele.
`example:
given number: 63240
the unit: 6
the number in the highest location:0
are both of them greater then 3 and 2 and4(middle) ? yes
result: true (for that case)
the quation is:
write a program that get a number from user, the program will print if the given number from the user is a happy number or not
I know how to find the units and the highest number location, but got stack figure it out how to
how to use the digits in the middle in order to find the answer for that..
notice that the only class we've learned so fat is Math,(not even string yes)
we also learned while and for but nothing so far..
I also know that in order to go through all digit in given number i need to use the while loop,
but I dont know how do I use it in order to use them to get to the answer..
my code so far:
int number;
int units;
int highestDigitLoc;
bool isHappyNumber = true;
int count = 0;
Console.WriteLine("enter a number:");
number = int.Parse(Console.ReadLine());
while(number > 0)
{
count++;
units = number % 10;
highestDigitLoc = number / 10;
}
thanks
This link explains what Happy Number's are in a simple way. Basically you have to keep suming the square of each digit present in the number, until the result equals 1. This proccess can go on indefinitely, but fortunately we know for certain that if the sum equals 4, it will never result in a Happy Number. Therefore, we can do the following:
private static bool IsHappy(int n)
{
if (n == 1)
return true;
else if (n == 0 || n == 4)
return false;
else
return IsHappy(SumDigitSquares(n));
}
private static int SumDigitSquares(int n)
{
if (n < 10)
return n * n;
else
return SumDigitSquares(n % 10) + SumDigitSquares(n / 10);
}
Usage:
bool result = IsHappy(63240); //false
Well, your question very vague, however, we can turn the number into an array of digits int[] digits
using System.Linq;
...
int[] digits = null;
while (true) {
Console.WriteLine("enter a number:");
// string : let's solve for arbitrary long numbers (no necessary int)
string number = Console.ReadLine().Trim();
if (string.IsNullOrEmpty(number))
Console.WriteLine("Empty string is not enough");
else if (number.All(c => c >= '0' && c <= '9')) {
// This code preserves leading zeroes
digits = number.Select(c => c - '0').ToArray();
// This code removes leading zeroes
//digits = number
// .SkipWhile(c => c == '0')
// .Select(c => c - '0')
// .DefaultIfEmpty()
// .ToArray();
break;
}
else
Console.Write("Not a valid integer value. Please, try again.");
}
Then we can use this int[] digits to implement any logic required.
Please, note, that we preserve leading zeroes:
"63240" -> int[] {6, 3, 4, 2, 0}
"063240" -> int[] {0, 6, 3, 4, 2, 0}
e.g.
let a number be happy if and only if
It contains at least 3 digits (in order to have middle ones)
Max of the first and last digits is greater than max of all the other digits
In our case with 63240
63240 has 5 digits, the condition holds
Max(0, 6) == 6 > Max(3, 2, 4) == 4, the condition holds
Code:
bool isHappyNumber =
digits.Length >= 3 &&
Math.Max(digits[0], digits[digits.Length - 1]) >
digits.Skip(1).Take(digits.Length - 2).Max();
Edit: let's implement isHappyNumber with good old for loops:
int maxFirstAndLast = digits[0] > digits[digits.Length - 1]
? digits[0]
: digits[digits.Length - 1];
int maxMiddle = 0;
for (int i = 1; i < digits.Length - 1; ++i)
if (digits[i] > maxMiddle) then
maxMiddle = digits[i];
bool isHappyNumber =
digits.Length >= 3 &&
maxFirstAndLast > maxMiddle;
//Remeber to add using System.Linq;
public static bool IsHappyNumber(int num)
{
var numbers = new List<int>();
while (true)
{
int sum = 0;
var digits = num.ToString().Select(x => int.Parse(x.ToString())).ToList();
foreach (var digit in digits)
sum += digit * digit;
if (numbers.Contains(sum))
break;
numbers.Add(sum);
num = sum;
}
return numbers.LastOrDefault() == 1;
}

Efficient way to count the number of appearances of a digit in a number

I need to count the number of times a single digit (not 0) appears in a number (positive integer) of varying length.
The obvious solution is to convert the number to a string, the digit to a character and iterate over the string to count the number of times the character appears in the string.
static int CountDigitInString(string searchString, char digit)
{
int sum = 0;
for (int i = 0; i < searchString.Length; i++)
{
if (searchString[i] == digit)
sum++;
}
return sum;
}
The problem with this method, however, is that it is too slow for my purposes as I am running it many times.
public static void Run()
{
for (int i = 0; i < 1000000; i++)
{
CountDigitInString(i.ToString(), (char)j);
}
}
After I noted that the process took too much time, the CPU sampling profiler showed me that the problem was with the conversion to string.
So, how do I efficiently count the number of times a digit (single digit only, not a number) appears in a number (of any length)?
Here is more optimized version of #shaitibber solution. It replaces one division with multiplying and returns 1 for 0,0. It is about 20% faster.
static int CountDigitsInString2(int number, int digit)
{
int sum = 0;
do
{
int n2 = number / 10;
if (number - n2 * 10 == digit)
sum++;
number = n2;
} while (number != 0);
return sum;
}
And here is solution about three times faster than that (but does not work for 0 digit, which is not required). It precalculates results for numbers 0..9999.
private static int[][] cache = new int[10][];
private const int cacheSize = 10000;//or 100000
private static int[] initCache(int digit)
{
var ca = cache[digit] = new int[cacheSize];
for (int i = 0; i < ca.Length; ++i)
{
ca[i] = CountDigitsInString2(i, digit);
}
return ca;
}
static int CountDigitsInString3(int number, int digit)
{
var ca = cache[digit] ?? initCache(digit);
int sum = 0;
while (number != 0)
{
int n2 = number / cacheSize;
sum += ca[number - n2 * cacheSize];
number = n2;
};
return sum;
}
I found a way which turned out to be about 3 times as fast on average (checked using a Stopwatch):
static int CountDigitsInString(int number, int digit)
{
int sum = 0;
while (number != 0)
{
if (number % 10 == digit)
sum++;
number /= 10;
}
return sum;
}
EDIT:
I found a way which is over 4 times as fast as the one above. Before I start, note that this solution is valid only for cases in which you are counting appearances of a digit in consecutive numbers.
It occurred to me that if you counted the number of times the digit "d" appeared in a number "A", then you don't neccessarily have to recount the number of times "d" appears in "A + 1" to know what it is.
For example, if I know that the digit 3 appears 4 times in the number 35312336, I can know for a fact that it will still appear 4 times in the next consecutive number 35312337, without actually counting.
The reason I can do this is that the count would only change in one of three cases:
1) When the last digit of "A - 1" was a 9, "A" can change entirely due to numbers being carried over. This is the only case in which we actually have to count (although you could, theoretically, optimize this further by checking the numbers carried over to see if they affect the total but this strikes me as overly complicated).
2) When the last digit of "A - 1" was "d - 1", we know that the number of times "d" appears in "A" has increased by one.
3) When the last digit of "A - 1" was "d", we know that the number of times "d" appears in "A" has decreased by one.
This means that you only have to count the appearances of "d" in "A" using arithmetical operations in one out of 10 cases!
public static void Run()
{
int digit = 1;
int count = 0;
for (int i = 0; i < 100000; i++)
{
int previousLastDigit = (i - 1) % 10;
if (previousLastDigit == (digit - 1))
count++;
else if (previousLastDigit == 9)
count = CountDigitsInString(i, digit);
else if (previousLastDigit == digit)
count--;
Console.WriteLine(digit + " appears " + count + " times in the number " + i);
}
}
The CountDigitsInString function is the one above.
Here is a little snip with LINQ to give you another way to do it (didn't ran a stopwatch)
var number = 11334511;
var digit = 1;
var digitAsChar = Convert.ToChar(digit.ToString().ToLower());
// Occurence will be 4
var occurence = number.ToString().ToLower().Count(s => s == digitAsChar);
I suggest you use LINQ on string.
Source: https://msdn.microsoft.com/en-us/library/mt693025.aspx
static int CountDigitInString(string number, char digit)
{
int count = number.Count(ns => ns == digit);
return count;
}

An algorithm for a number divisible to n

At first user gives a number (n) to program, for example 5.
the program must find the smallest number that can be divided to n (5).
and this number can only consist of digits 0 and 9 not any other digits.
for example if user gives 5 to program.
numbers that can be divided to 5 are:
5, 10, 15, 20, 25, 30, ..., 85, 90, 95, ...
but 90 here is the smallest number that can be divided to 5 and also consist of digits (0 , 9). so answer for 5 must be 90.
and answer for 9 is 9, because it can be divided to 9 and consist of digit (9).
my code
string a = txtNumber.Text;
Int64 x = Convert.ToInt64(a);
Int64 i ,j=1,y=x;
bool t = false;
for (i = x + 1; t == false; i++)
{
if (i % 9 == 0 && i % 10 == 0 && i % x == 0)
{
j = i;
for (; (i /= 10) != 0; )
{
i /= 10;
if (i == 0)
t = true;
continue;
}
}
}
lblAnswer.Text = Convert.ToString(j);
If you're happy to go purely functional then this works:
Func<IEnumerable<long>> generate = () =>
{
Func<long, IEnumerable<long>> extend =
x => new [] { x * 10, x * 10 + 9 };
Func<IEnumerable<long>, IEnumerable<long>> generate2 = null;
generate2 = ns =>
{
var clean = ns.Where(n => n > 0).ToArray();
return clean.Any()
? clean.Concat(generate2(clean.SelectMany(extend)))
: Enumerable.Empty<long>();
};
return generate2(new[] { 9L, });
};
Func<long, long?> f = n =>
generate()
.Where(x => x % n == 0L)
.Cast<long?>()
.FirstOrDefault();
So rather than iterate through all possible values and test for 0 & 9 and divisibility, this just generates only numbers with 0 & 9 and then only tests for visibility. It is much faster this way.
I can call it like this:
var result = f(5L); // 90L
result = f(23L); //990909L
result = f(123L); //99999L
result = f(12321L); //90900999009L
result = f(123212L); //99909990090000900L
result = f(117238L); //990990990099990990L
result = f(1172438L); //null == No answer
These results are super fast. f(117238L) returns a result on my computer in 138ms.
You can try this way :
string a = txtNumber.Text;
Int64 x = Convert.ToInt64(a);
int counter;
for (counter = 1; !isValid(x * counter); counter++)
{
}
lblAnswer.Text = Convert.ToString(counter*x);
code above works by searching multiple of x incrementally until result that satisfy criteria : "consist of only 0 and or 9 digits" found. By searching only multiple of x, it is guaranteed to be divisible by x. So the rest is checking validity of result candidate, in this case using following isValid() function :
private static bool isValid(int number)
{
var lastDigit = number%10;
//last digit is invalid, return false
if (lastDigit != 0 & lastDigit != 9) return false;
//last digit is valid, but there is other digit(s)
if(number/10 >= 1)
{
//check validity of digit(s) before the last
return isValid(number/10);
}
//last digit is valid, and there is no other digit. return true
return true;
}
About strange empty for loop in snippet above, it is just syntactic sugar, to make the code a bit shorter. It is equal to following while loop :
counter = 1;
while(!isValid(input*counter))
{
counter++;
}
Use this simple code
int inputNumber = 5/*Or every other number, you can get this number from input.*/;
int result=1;
for (int i = 1; !IsOk(result,inputNumber); i++)
{
result = i*inputNumber;
}
Print(result);
IsOk method is here:
bool IsOk(int result, int inputNumber)
{
if(result%inputNumber!=0)
return false;
if(result.ToString().Replace("9",string.Empty).Replace("0",string.Empty).Length!=0)
return false;
return true;
}
My first solution has very bad performance, because of converting a number to string and looking for characters '9' and '0'.
New solution:
My new solution has very good performance and is a technical approach since of using Breadth-first search(BFS).
Algorithm of this solution:
For every input number, test 9, if it is answer print it, else add 2 child numbers (90 & 99) to queue, and continue till finding answer.
int inputNumber = 5;/*Or every other number, you can get this number from input.*/
long result;
var q = new Queue<long>();
q.Enqueue(9);
while (true)
{
result = q.Dequeue();
if (result%inputNumber == 0)
{
Print(result);
break;
}
q.Enqueue(result*10);
q.Enqueue(result*10 + 9);
}
Trace of number creation:
9
90,99
900,909,990,999
9000,9009,9090,9099,9900,9909,9990,9999
.
.
.
I wrote this code for console, and i used goto command however it is not prefered but i could not write it with only for.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace main
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter your number");
Int64 x = Convert.ToInt64(Console.ReadLine());
Int64 y, j, i, k, z = x;
x = x + 5;
loop:
x++;
for (i = 0, y = x; y != 0; i++)
y /= 10;
for (j = x, k = i; k != 0; j /= 10, k--)
{
if (j % 10 != 9)
if (j % 10 != 0)
goto loop;
}
if (x % z != 0)
goto loop;
Console.WriteLine("answer:{0}",x);
Console.ReadKey();
}
}
}

Find the number

This is a problem statement.
Consider a number 2345. If you multiply its digits then you get the number 120. Now if you again multiply digits of 120 then you will get number 0 which is a one digit number. If I add digits of 2345 then I will get 14. If I add digits of 14 then I will get 5 which is a one digit number.
Thus any number can be converted into two one digit numbers in some number of steps. You can see 2345 is converted to 0 by using multiplication of digits in 2 steps and it is converted to 5 by using addition of digits in 2 steps. Now consider any number N. Let us say that it can be converted by multiplying digits to a one digit number d1 in n1 steps and by adding digits to one digit number d2 in n2 steps.
Your task is to find smallest number greater than N and less than 1000000000 which can be converted by multiplying its digits to d1 in less than or equal to n1 steps and by adding its digits to d2 in less than or equal to n2 steps.
How to solve it in C#...
I think you're simply approaching / interpreting the problem incorrectly; here's a stab in the dark:
using System;
using System.Diagnostics;
static class Program
{
static void Main()
{
// check our math first!
// You can see 2345 is converted to 0 by using multiplication of digits in 2 steps
int value, steps;
value = MultiplyToOneDigit(2345, out steps);
Debug.Assert(value == 0);
Debug.Assert(steps == 2);
// and it is converted to 5 by using addition of digits in 2 steps
value = SumToOneDigit(2345, out steps);
Debug.Assert(value == 5);
Debug.Assert(steps == 2);
// this bit is any random number
var rand = new Random();
for (int i = 0; i < 10; i++)
{
int N = rand.Next(0, MAX);
int result = Execute(N);
Console.WriteLine("For N={0}, our answer is {1}", N, result);
}
}
const int MAX = 1000000000;
//Now consider any number N.
static int Execute(int N)
{
// Let us say that it can be converted by multiplying digits to a one digit number d1 in n1
// steps and by adding digits to one digit number d2 in n2 steps.
int n1, n2;
int d1 = MultiplyToOneDigit(N, out n1),
d2 = SumToOneDigit(N, out n2);
// Your task is to find smallest number greater than N and less than 1000000000
for (int i = N + 1; i < MAX; i++)
{
int value, steps;
// which can be converted by multiplying its digits to d1 in less than or equal to n1 steps
value = MultiplyToOneDigit(i, out steps);
if (value != d1 || steps > n1) continue; // no good
// and by adding its digits to d2 in less than or equal to n2 steps.
value = SumToOneDigit(i, out steps);
if(value != d2 || steps > n2) continue; // no good
return i;
}
return -1; // no answer
}
static int MultiplyToOneDigit(int value, out int steps)
{
steps = 0;
while (value > 10)
{
value = MultiplyDigits(value);
steps++;
}
return value;
}
static int SumToOneDigit(int value, out int steps)
{
steps = 0;
while (value > 10)
{
value = SumDigits(value);
steps++;
}
return value;
}
static int MultiplyDigits(int value)
{
int acc = 1;
while (value > 0)
{
acc *= value % 10;
value /= 10;
}
return acc;
}
static int SumDigits(int value)
{
int total = 0;
while (value > 0)
{
total += value % 10;
value /= 10;
}
return total;
}
}
There are two memory problems I can see; the first is the generation of lots of strings - you might want to approach that something like:
static int SumDigits(int value)
{
int total = 0;
while (value > 0)
{
total += value % 10;
value /= 10;
}
return total;
}
(which is completely untested)
The second problem is the huge list; you don't need to store (in lstString) every value just to find a minimum. Just keep track of the best you've done so far. Or if you need the data for every value, then: don't store them as a string. Indeed, the i can be implied anyway (from the position in the list/array), so all you would really need would be an int[] of the cnt values for every value. And int[1000000000] is 4GB just by itself, so would require the large-array support in recent .NET versions (<gcAllowVeryLargeObjects>). But much better would be: just don't store it.
But it's throwing System.OutOfMemoryException .
That simply mean you're running out of memory. Your limit is 1,000,000,000 or roughly 1G. Times 4 bytes for a string reference that's already too large for a 32 bit system. Even without the actual strings.
You can store your answers more compactly in an int[] array but that would still show the same problem.
So, lower your limit or compile and run on a 64 bit PC.
A for effort :)
Now doing together. You can of course do refactoring.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _17082903_smallest_greatest_number
{
class Program
{
static void Main(string[] args)
{
int N = 2344;
int n1 = 0;
int n2 = 0;
int d1 = SumDigits(N, ref n1);
int d2 = ProductDigits(N, ref n2);
bool sumFound = false, productFound = false;
for (int i = N + 1; i < 1000000000; i++)
{
if (!sumFound)
{
int stepsForSum = 0;
var res = SumDigits(i, ref stepsForSum);
if (res == d1 && stepsForSum <= n1)
{
Console.WriteLine("the smallest number for sum is: " + i);
Console.WriteLine(string.Format("sum result is {0} in {1} steps only", res, stepsForSum));
sumFound = true;
}
stepsForSum = 0;
}
if (!productFound)
{
int stepsForProduct = 0;
var res2 = ProductDigits(i, ref stepsForProduct);
if (res2 == d2 && stepsForProduct <= n2)
{
Console.WriteLine("the smallest number for product is: " + i);
Console.WriteLine(string.Format("product result is {0} in {1} steps only", res2, stepsForProduct));
productFound = true;
}
stepsForProduct = 0;
}
if (productFound && sumFound)
{
break;
}
}
}
static int SumDigits(int value, ref int numOfSteps)
{
int total = 0;
while (value > 0)
{
total += value % 10;
value /= 10;
}
numOfSteps++;
if (total < 10)
{
return total;
}
else
{
return SumDigits(total, ref numOfSteps);
}
}
static int ProductDigits(int value, ref int numOfSteps)
{
int total = 1;
while (value > 0)
{
total *= value % 10;
value /= 10;
}
numOfSteps++;
if (total < 10)
{
return total;
}
else
{
return ProductDigits(total, ref numOfSteps);
}
}
}
}

Split number into groups of 3 digits

I want to make a method that takes a variable of type int or long and returns an array of ints or longs, with each array item being a group of 3 digits. For example:
int[] i = splitNumber(100000);
// Outputs { 100, 000 }
int[] j = splitNumber(12345);
// Outputs { 12, 345 }
int[] k = splitNumber(12345678);
// Outputs { 12, 345, 678 }
// Et cetera
I know how to get the last n digits of a number using the modulo operator, but I have no idea how to get the first n digits, which is the only way to make this method that I can think of. Help please!
Without converting to string:
int[] splitNumber(int value)
{
Stack<int> q = new Stack<int>();
do
{
q.Push(value%1000);
value /= 1000;
} while (value>0);
return q.ToArray();
}
This is simple integer arithmetic; first take the modulo to get the right-most decimals, then divide to throw away the decimals you already added. I used the Stack to avoid reversing a list.
Edit: Using log to get the length was suggested in the comments. It could make for slightly shorter code, but in my opinion it is not better code, because the intent is less clear when reading it. Also, it might be less performant due to the extra Math function calls. Anyways; here it is:
int[] splitNumber(int value)
{
int length = (int) (1 + Math.Log(value, 1000));
var result = from n in Enumerable.Range(1,length)
select ((int)(value / Math.Pow(1000,length-n))) % 1000;
return result.ToArray();
}
By converting into a string and then into int array
int number = 1000000;
string parts = number.ToString("N0", new NumberFormatInfo()
{
NumberGroupSizes = new[] { 3 },
NumberGroupSeparator = "."
});
By using Maths,
public static int[] splitNumberIntoGroupOfDigits(int number)
{
var numberOfDigits = Math.Floor(Math.Log10(number) + 1); // compute number of digits
var intArray = new int[Convert.ToInt32(numberOfDigits / 3)]; // we know the size of array
var lastIndex = intArray.Length -1; // start filling array from the end
while (number != 0)
{
var lastSet = number % 1000;
number = number / 1000;
if (lastSet == 0)
{
intArray[lastIndex] = 0; // set of zeros
--lastIndex;
}
else if (number == 0)
{
intArray[lastIndex] = lastSet; // this could be your last set
--lastIndex;
}
else
{
intArray[lastIndex] = lastSet;
--lastIndex;
}
}
return intArray;
}
Try converting it to string first and do the parsing then convert it back to number again
Convert to string
Get length
If length modulus 3 == 0
String substring it into ints every 3
else if
Find remainder such as one or two left over
Substring remainder off of front of string
Then substring by 3 for the rest
You can first find out how large the number is, then use division to get the first digits, and modulo to keep the rest:
int number = 12345678;
int len = 1;
int div = 1;
while (number >= div * 1000) {
len++;
div *= 1000;
}
int[] result = new int[len];
for (int i = 0; i < result.Length; i++) {
result[i] = number / div;
number %= div;
div /= 1000;
}
You can use this with the System.Linq namespace from .NET 3.5 and above:
int[] splitNumber(long value)
{
LinkedList<int> results = new LinkedList<int>();
do
{
int current = (int) (value % 1000);
results.AddFirst(current);
value /= 1000;
} while (value > 0);
return results.ToArray();// Extension method
}
I use LinkedList<int> to avoid having to Reverse a list before returning. You could also use Stack<int> for the same purpose, which would only require .NET 2.0:
int[] splitNumber(long value)
{
Stack<int> results = new Stack<int>();
do
{
int current = (int) (value % 1000);
results.Push(current);
value /= 1000;
} while (value > 0);
return results.ToArray();
}

Categories

Resources