Как преобразовать Int в строку в C# без использования ToString ()?




преобразуйте следующий аргумент int в строку без использования каких-либо собственных функций toString.



public string integerToString(int integerPassedIn){    
//Your code here
}



так как все наследуется от Object и Object есть ToString() метод как бы вы преобразовали int до string без использования уроженца ToString() способ?



проблема с конкатенацией строк заключается в том, что он будет вызывать ToString() вверх по цепочке, пока он не ударит один или не ударит Object класса.



как сделать преобразовать целое число в строку в C# без использования ToString()?

1121   10  

10 ответов:

что-то вроде этого:

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;
}

обновление: вот еще одна версия, которая короче и должна работать намного лучше, так как она устраняет всю конкатенацию строк в пользу манипулирования массивом фиксированной длины. Он поддерживает базы до 16, но было бы легко расширить его до более высоких баз. Это, вероятно, можно было бы улучшить дальше:

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);
}

Это решение я всегда использую:

    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;
    }

это выглядит довольно сложно, но имеет следующие особенности:

  • поддерживает системы счисления от 2 до 36
  • обрабатывает отрицательные значения
  • дополнительно общее количество цифр

Я действительно не убежден в конкатенации operator + звонки ToString, а если это действительно так, вы можете избежать этих двух, делая что-то вроде следующего:

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());

целое число обрабатывается от наименее значимой цифры до наиболее значимой. Одна цифра вычисляется по модулю 10 (%10), который затем добавляется к значению символа '0'. Это приводит к одному из символов '0', '1',... , '9'.

цифры помещаются в стек, потому что они должны быть представлены в обратном порядке по мере их обработки (от наиболее значимой цифры до наименее значимой цифры). Делая это так, вместо того, чтобы многократно добавлять цифры чтобы строка могла быть более эффективной, но поскольку количество цифр довольно мало, вам придется выполнить тест, чтобы быть уверенным.

какой-то дополнительной обработки не требуется отрегулировать non-положительные числа.

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());
}

моя первая версия использовала StringBuilder чтобы создать строку из массива символов, но получить строку "из"StringBuilder требуется вызов метода с именем ToString. Очевидно, этот метод не делает никакого преобразования int в строку, которая мне о чем этот вопрос.

но чтобы доказать, что вы можете создать строку без вызова ToString я переключился на использование string конструктор, который я также предполагаю, чтобы быть более эффективным по сравнению с использованием StringBuilder.

и если ToString в любой форме запрещено, нельзя использовать конкатенацию строк, как показано в документации string.Concat:

метод объединяет arg0 и arg1by, вызывая без параметров ToString метод arg0 и arg1; он не добавляет никаких разделителей.

поэтому выполнение s += '1' будем называть '1'.ToString(). Но для меня это не важно. Важная часть как преобразовать int в String.

стремясь к более короткой версии, и тот, который использует 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;
}

использование new string(..., 1) конструктор-это просто способ удовлетворить требование OP, что ToString не вызываться ни на что.

вот мой берет на него с помощью итерации и рекурсии с анализом времени выполнения.

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];
    }
}


Ключевые Моменты

  • обрабатывает основание 2 до 36 (предостережение: вы должны будете убедиться, что ваша база верна, так как нет обработки исключений.
  • метод рекурсии составляет всего 3 строк! (код гольф стиль)

анализ

ниже приведен анализ времени выполнения обоих методов по сравнению со стандартом ToString() на моем компьютере.

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

результаты показывают, что методы итерации и рекурсии выполняются в 5.49 и 5.00 раз медленнее, чем стандартные ToString() метод.

и вот код, который я использовал для анализа:

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();
    }

вы можете конвертировать любую цифру в символ, как это

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

магическое число 48 - это значение ASCII символа 0 и они являются последовательными в таблице ASCII, таким образом, вы можете просто добавить цифру, чтобы получить соответствующее значение в таблице ASCII. и вы можете получить цифры в целое число итеративно с помощью оператора модуля % Заимствование общей структуры из pswg вы получите

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
}
    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());
    }

рекурсия:

    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);
    }

Если это c++, то:

public string IntToString(int a){    
  char rc[20];
  int x = a;
  if(a < 0) x = -x;
  char *p = rc + 19;
  *p = 0;
  do 
    *--p = (x % 10) | '0';
  while(x /= 10);
  if(a < 0) *--p = '-';
  return string(p);
}

Comments

    Ничего не найдено.