How do I convert an Int to a String in C# without using ToString()?

C#StringAlgorithmInt

C# Problem Overview


>Convert the following int argument into a string without using any native toString functionality. > public string integerToString(int integerPassedIn){
//Your code here }

Since everything inherits from Object and Object has a ToString() method how would you convert an int to a string without using the native ToString() method?

The problem with string concatenation is that it will call ToString() up the chain until it hits one or hits the Object class.

How do you convert an integer to a string in C# without using ToString()?

C# Solutions


Solution 1 - C#

Something like this:

public string IntToString(int a)
{    
    var chars = new[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
    var str = string.Empty;
    if (a == 0)
    {
        str = chars[0];
    }
    else if (a == int.MinValue)
    {
        str = "-2147483648";
    }
    else
    {
        bool isNegative = (a < 0);
        if (isNegative)
        {
            a = -a;
        }

        while (a > 0)
        {
            str = chars[a % 10] + str;
            a /= 10;
        }

        if (isNegative)
        {
            str = "-" + str;
        }
    }

    return str;
}

Update: Here's another version which is shorter and should perform much better, since it eliminates all string concatenation in favor of manipulating a fixed-length array. It supports bases up to 16, but it would be easy to extend it to higher bases. It could probably be improved further:

public string IntToString(int a, int radix)
{
    var chars = "0123456789ABCDEF".ToCharArray();
    var str = new char[32]; // maximum number of chars in any base
    var i = str.Length;
    bool isNegative = (a < 0);
    if (a <= 0) // handles 0 and int.MinValue special cases
    {
        str[--i] = chars[-(a % radix)];
        a = -(a / radix);
    }
    
    while (a != 0)
    {
        str[--i] = chars[a % radix];
        a /= radix;
    }

    if (isNegative)
    {
        str[--i] = '-';
    }

    return new string(str, i, str.Length - i);
}

Solution 2 - C#

This is the solution I always use:

    public static string numberBaseChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    public static string IntToStringWithBase(int n, int b) {
        return IntToStringWithBase(n, b, 1);
    }

	public static string IntToStringWithBase(int n, int b, int minDigits) {
		if (minDigits < 1) minDigits = 1;
		if (n == 0) return new string('0', minDigits);
		string s = "";
		if ((b < 2) || (b > numberBaseChars.Length)) return s;
		bool neg = false;
		if ((b == 10) && (n < 0)) { neg = true; n = -n; }
		uint N = (uint)n;
		uint B = (uint)b;
		while ((N > 0) | (minDigits-- > 0)) {
			s = numberBaseChars[(int)(N % B)] + s;
			N /= B;
		}
		if (neg) s = "-" + s;
		return s;
	}

This looks quite complicated but has the following features:

  • Supports radix 2 to 36
  • Handles negative values
  • Optional total number of digits

Solution 3 - C#

I am not truly convinced the concatenation operator + calls ToString, but if that is indeed true, you can avoid those two by doing something like the following:

if (a == 0) return "0";   

/* Negative maxint doesn't have a corresponding positive value, so handle it
 * as a special case. Thanks to @Daniel for pointing this out.
 */
if (a == 0x80000000) return "-2147483648";

List<char> l = new List<char>();
bool negative = false;

if (a < 0) 
{
    negative = true;
    a *= -1;
}

while (a > 0)
{
    l.Add('0' + (char)(a % 10));
    a /= 10;
}

if (negative) l.Add('-');

l.Reverse();

return new String(l.ToArray());

Solution 4 - C#

The integer is processed from the least significant digit to the most significant. A single digit is computed used modulo 10 (%10) which is then added to the character value of '0'. This results in one of the characters '0', '1', ... , '9'.

The digits are pushed onto a stack because they have to be presented in the reverse order as they are processed (most significant digit to least significant digit). Doing it like this instead of repeatedly prepending the digits to a string could be more efficient but because the number of digits is quite low you would have to perform a benchmark to be sure.

Some extra processing is required to handle non-positive numbers.

public string IntToString(int a) {
  if (a == 0)
    return "0";
  if (a == int.MinValue)
    return "-2147483648";
  var isNegative = false;
  if (a < 0) {
    a = -a;
    isNegative = true;
  }
  var stack = new Stack<char>();
  while (a != 0) {
    var c = a%10 + '0';
    stack.Push((char) c);
    a /= 10;
  }
  if (isNegative)
    stack.Push('-');
  return new string(stack.ToArray());
}

My first version used a StringBuilder to create the string from the array of characters but getting the string "out of the" StringBuilder requires a call to method named ToString. Obviously, this method does not do any int to string conversion which to me is what this question is about.

But to prove that you can create a string without calling ToString I have switched to using a string constructor which I also would assume to be more efficient compared to using a StringBuilder.

And if ToString in any form is prohibited you cannot use string concatenation as seen in the documentation for string.Concat:

> The method concatenates arg0 and arg1by calling the parameterless ToString method of arg0 and arg1; it does not add any delimiters.

so executing s += '1' will call '1'.ToString(). But to me this isn't important. The important part is how you convert an int to a string.

Solution 5 - C#

you can convert any digit to a char like this

byte = (char)(byte)(digit+48)

The magic number 48 is the ASCII value of the char 0 and they are sequential in the ASCII table thus you can just add the digit to get the corresponding value in the ASCII table. and you can get the digits in the integer iteratively using the modulus operator % Borrowing the general structure from pswg you would get

public string IntToString(int a) {
  var str = string.Empty;
    bool isNegative = false;
    if (a < 0) {
        isNegative = true;
        a = -a;
    }

    do {
        str = (char)(byte)((a % 10) + 48) + str;
        a /= 10;
    } while(a > 0);

    return isNegative ? '-' + str : str
}

Solution 6 - C#

Aiming for a shorter version, and one that uses Math.DivRem:

string IntToString(int a)
{
    if (a == int.MinValue)
        return "-2147483648";
    if (a < 0)
        return "-" + IntToString(-a);
    if (a == 0)
        return "0";
    var s = "";
    do
    {
        int r;
        a = Math.DivRem(a, 10, out r);
        s = new string((char)(r + (int)'0'), 1) + s;
    }
    while (a > 0);
    return s;
}

The use of the new string(..., 1) constructor is just a way to satisfy the OP's requirement that ToString not be called on anything.

Solution 7 - C#

Here are my takes on it using iteration and recursion with run time analysis.

public static class IntegerToString
{
    static char[] d = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();

    public static string Iteration(int num, int radix = 10)
    {
        if (num == 0) return "0";
        if (num < 0) return "-" + Iteration(Math.Abs(num));
        var r = new List<char>();
        while (num > 0)
        {
            r.Insert(0, d[num % radix]);
            num /= radix;
        }
        return new string(r.ToArray());
    }

    public static string Recursion(int num, int radix = 10)
    {
        if (num == 0) return "0";
        if (num < 0) return "-" + Recursion(Math.Abs(num));
        return (num > radix - 1 ? Recursion(num / radix) : "") + d[num % radix];
    }
}


Key Points
  • Handles base 2 up to 36 (CAVEAT: you'll have to ensure your base is correct since there is no exception handling.
  • Recursion method is only 3 lines long! (code golf style)
Analysis

The following is the runtime analysis of both methods compared to the standard ToString() on my computer.

50 runs of 100000 items per set

Running Time:
Iteration: 00:00:02.3459591 (00:00:00.0469191 avg)
Recursion: 00:00:02.1359731 (00:00:00.0427194 avg)
Standard : 00:00:00.4271253 (00:00:00.0085425 avg)

Ratios:
     | Iter | Rec  | Std
-----+------+------+-----
Iter | 1.00 | 0.91 | 0.18
Rec  | 1.10 | 1.00 | 0.20
Std  | 5.49 | 5.00 | 1.00

The results indicate the iteration and recursion methods run 5.49 and 5.00 times slower than the standard ToString() method.

And here is the code I used for the analysis:

class Program
{
    static void Main(string[] args)
    {
        var r = new Random();
        var sw = new System.Diagnostics.Stopwatch();

        var loop = new List<long>();
        var recr = new List<long>();
        var std = new List<long>();
        var setSize = 100000;
        var runs = 50;

        Console.WriteLine("{0} runs of {1} items per set", runs, setSize);

        for (int j = 0; j < runs; j++)
        {
            // create number set
            var numbers = Enumerable.Range(1, setSize)
                                    .Select(s => r.Next(int.MinValue,
                                                        int.MaxValue))
                                    .ToArray();

            // loop
            sw.Start();
            for (int i = 0; i < setSize; i++)
                IntegerToString.Iteration(numbers[i]);
            sw.Stop();
            loop.Add(sw.ElapsedTicks);

            // recursion
            sw.Reset();
            sw.Start();
            for (int i = 0; i < setSize; i++)
                IntegerToString.Recursion(numbers[i]);
            sw.Stop();
            recr.Add(sw.ElapsedTicks);

            // standard
            sw.Reset();
            sw.Start();
            for (int i = 0; i < setSize; i++)
                numbers[i].ToString();
            sw.Stop();
            std.Add(sw.ElapsedTicks);
        }

        Console.WriteLine();
        Console.WriteLine("Running Time:");
        Console.WriteLine("Iteration: {0} ({1} avg)", 
                          TimeSpan.FromTicks(loop.Sum()),
                          TimeSpan.FromTicks((int)loop.Average()));
        Console.WriteLine("Recursion: {0} ({1} avg)", 
                          TimeSpan.FromTicks(recr.Sum()),
                          TimeSpan.FromTicks((int)recr.Average()));
        Console.WriteLine("Standard : {0} ({1} avg)", 
                          TimeSpan.FromTicks(std.Sum()),
                          TimeSpan.FromTicks((int)std.Average()));

        double lSum = loop.Sum();
        double rSum = recr.Sum();
        double sSum = std.Sum();

        Console.WriteLine();
        Console.WriteLine("Ratios: \n" +
                          "     | Iter | Rec  | Std \n" +
                          "-----+------+------+-----");
        foreach (var div in new[] { new {n = "Iter", t = lSum}, 
                                    new {n = "Rec ", t = rSum},
                                    new {n = "Std ", t = sSum}})
            Console.WriteLine("{0} | {1:0.00} | {2:0.00} | {3:0.00}", 
                              div.n, lSum / div.t, rSum / div.t, sSum / div.t);

        Console.ReadLine();
    }

Solution 8 - C#

    public static string integerToString(int integerPassedIn)
    {
        if (integerPassedIn == 0) return "0";
        var negative = integerPassedIn < 0;
        var res = new List<char>();
        while(integerPassedIn != 0)
        {
           res.Add((char)(48 + Math.Abs(integerPassedIn % 10)));
           integerPassedIn /= 10;
        }
        res.Reverse();
        if (negative) res.Insert(0, '-');
        return new string(res.ToArray());
    }

Solution 9 - C#

Recursion:

    public static string integerToString(int integerPassedIn)
    {
        ICollection<char> res = new List<char>();
        IntToStringRecusion(integerPassedIn, res);
        if (integerPassedIn < 0) res.Add('-');
        return new string(res.Reverse().ToArray()).PadLeft(1,'0');
    }

    static void IntToStringRecusion(int integerPassedIn, ICollection<char> array)
    {
        if (integerPassedIn == 0) return;
        array.Add((char)(48 + Math.Abs(integerPassedIn % 10)));
        IntToStringRecusion(integerPassedIn / 10, array);
    }

Solution 10 - C#

easy peasy:

string s = 5 + ""
//s = "5"

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAnthony RussellView Question on Stackoverflow
Solution 1 - C#p.s.w.gView Answer on Stackoverflow
Solution 2 - C#joeView Answer on Stackoverflow
Solution 3 - C#lc.View Answer on Stackoverflow
Solution 4 - C#Martin LiversageView Answer on Stackoverflow
Solution 5 - C#Rune FSView Answer on Stackoverflow
Solution 6 - C#Timothy ShieldsView Answer on Stackoverflow
Solution 7 - C#Alex EssilfieView Answer on Stackoverflow
Solution 8 - C#deepee1View Answer on Stackoverflow
Solution 9 - C#deepee1View Answer on Stackoverflow
Solution 10 - C#person the humanView Answer on Stackoverflow