ネイティブのtoString機能を使用せずに、次のint引数を文字列に変換します。
_public string integerToString(int integerPassedIn){ //Your code here }
_
すべてがObject
から継承し、Object
にはToString()
メソッドがあるため、ネイティブを使用せずにint
をstring
に変換するにはどうすればよいですかToString()
メソッド?
文字列の連結の問題は、チェーンに到達するか、Object
クラスに到達するまで、チェーンでToString()
を呼び出すことです。
ToString()
を使用せずにC#で整数を文字列に変換するにはどうすればよいですか?
このようなもの:
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;
}
これは非常に複雑に見えますが、次の機能があります。
連結を本当に確信していない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());
整数は、最下位桁から最上位桁まで処理されます。モジュロ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
を使用して文字の配列から文字列を作成しましたが、文字列を "out of the" StringBuilder
にするには、ToString
というメソッドを呼び出す必要があります。明らかに、このメソッドは文字列変換にintを行いません。これは私にとってこの質問の目的です。
しかし、ToString
を呼び出さずに文字列を作成できることを証明するために、string
コンストラクターを使用するように切り替えました。これは、StringBuilder
を使用するよりも効率的であると仮定します。
また、何らかの形式のToString
が禁止されている場合は、 _string.Concat
_ のドキュメントに記載されている文字列連結を使用できません。
このメソッドは、arg0とarg1のパラメーターなしのToStringメソッドを呼び出して、arg0とarg1を連結します。区切り文字は追加されません。
したがって、_s += '1'
_を実行すると'1'.ToString()
が呼び出されます。しかし、私にとってこれは重要ではありません。重要な部分は、intを文字列に変換する方法です。
短いバージョンと、_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];
}
}
_
以下は、私のコンピューターの標準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
_
結果は、反復メソッドおよび再帰メソッドの実行が、標準のToString()
メソッドより5.49および5.00倍遅いことを示しています。
そして、分析に使用したコードは次のとおりです。
_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 charの値0
であり、ASCIIテーブルで連続しているため、 ASCIIテーブルで対応する値を取得するために数字を追加します。また、モジュラス演算子%
を使用して整数の数字を繰り返し取得できます。
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());
}
これが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);
}
再帰:
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);
}