57

ネイティブの toString 機能を使用せずに、次の int 引数を文字列に変換します。

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

すべてがから継承し、メソッドObjectObject持っているので、ネイティブメソッドを使用せずToString()にどのように を に変換しますintか?stringToString()

文字列連結の問題は、チェーンが 1 つまたはクラスToString()にヒットするまでチェーンを呼び出すことです。Object

を使用せずにC#で整数を文字列に変換するにはどうすればよいですToString()か?

4

10 に答える 10

22

これは私がいつも使用するソリューションです:

    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 をサポート
  • 負の値を処理します
  • オプションの総桁数
于 2013-07-10T16:05:00.210 に答える
10

私は連結operator +呼び出しについて本当に確信が持てませんToStringが、それが本当なら、次のようなことをすることでこれら2つを避けることができます:

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());
于 2013-07-10T16:03:18.043 に答える
5

整数は、最下位桁から最上位桁に向かって処理されます。モジュロ 10 (%10) を使用して 1 桁が計算され、文字値 '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では、文字の配列から文字列を作成するために a を使用していましたが、「から」文字列を取得するには、StringBuilderという名前のメソッドを呼び出す必要がありますToString。明らかに、このメソッドは int から文字列への変換を行いません。これが私にとってこの質問の目的です。

しかし、呼び出しなしで文字列を作成できることを証明するために、コンストラクターToStringの使用に切り替えました。これは、 .stringStringBuilder

またToString、いずれかの形式が禁止されている場合は、次のドキュメントに記載されているように文字列連結を使用できませんstring.Concat

このメソッドは、arg0 と arg1 のパラメーターなしの ToString メソッドを呼び出して、arg0 と arg1 を連結します。区切り文字は追加されません。

したがって、実行するs += '1'と が呼び出されます'1'.ToString()。しかし、私にとってこれは重要ではありません。重要な部分は、int を文字列に変換する方法です。

于 2013-07-10T16:05:10.707 に答える
4

より短いバージョンと、次を使用するバージョンを目指しています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ません。

于 2013-07-10T16:40:39.967 に答える
3

これは、ランタイム分析による反復と再帰を使用した私の見解です。

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();
    }
于 2013-07-18T14:25:11.690 に答える
1
    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());
    }
于 2013-07-10T19:02:08.393 に答える