Подтвердить что ты не робот

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

    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
  • Обрабатывает отрицательные значения
  • Дополнительное общее количество цифр

Ответ 3

Я не уверен, что конкатенация 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());

Ответ 4

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

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

Для обработки неположительных чисел требуется некоторая дополнительная обработка.

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 для создания строки из массива символов, но для получения строки "out of" StringBuilder требуется вызов метода с именем ToString. Очевидно, что этот метод не делает никакого преобразования int для преобразования, которое для меня является вопросом, о котором идет речь.

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

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

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

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

Ответ 5

Нарисуйте для более короткой версии и использующую 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 не вызывалось ни на что.

Ответ 6

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

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

Магическое число 48 - это значение ASCII char 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
}

Ответ 7

Вот мои рекомендации по использованию итерации и рекурсии с анализом времени выполнения.

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


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

  • Ручки base 2 до 36 ( CAVEAT:, вам нужно будет убедиться, что ваша база правильная, поскольку обработка исключений не существует.
  • Метод рекурсии длится всего 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();
    }

Ответ 8

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

Ответ 9

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

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

Ответ 10

рекурсии:

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