Convertissez l'argument int suivant en chaîne sans utiliser de fonctionnalité native toString.
public string integerToString(int integerPassedIn){ //Your code here }
Comme tout hérite de Object
et Object
a une méthode ToString()
comment convertir un int
en string
sans utiliser le natif ToString()
méthode?
Le problème avec la concaténation de chaînes est qu'elle appellera ToString()
en haut de la chaîne jusqu'à ce qu'elle atteigne une ou frappe la classe Object
.
Comment convertir un entier en chaîne en C # sans utiliser ToString()
?
Quelque chose comme ça:
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;
}
Mise à jour: Voici une autre version qui est plus courte et devrait fonctionner beaucoup mieux, car elle élimine toute concaténation de chaînes en faveur de la manipulation d'un tableau de longueur fixe. Il prend en charge des bases jusqu'à 16, mais il serait facile de l'étendre à des bases plus élevées. Il pourrait probablement être encore amélioré:
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);
}
Voici la solution que j'utilise toujours:
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;
}
Cela semble assez compliqué mais présente les caractéristiques suivantes:
Je ne suis pas vraiment convaincu de la concaténation operator +
appelle ToString
, mais si c'est effectivement le cas, vous pouvez éviter ces deux en faisant quelque chose comme ceci:
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());
L'entier est traité du chiffre le moins significatif au plus significatif. Un seul chiffre est calculé à l'aide du modulo 10 (% 10) qui est ensuite ajouté à la valeur de caractère "0". Il en résulte l'un des caractères "0", "1", ..., "9".
Les chiffres sont poussés sur une pile car ils doivent être présentés dans l'ordre inverse lors de leur traitement (chiffre le plus significatif au chiffre le moins significatif). Le faire comme ceci au lieu de rajouter plusieurs fois les chiffres à une chaîne pourrait être plus efficace, mais comme le nombre de chiffres est assez faible, vous devrez effectuer un test de performance pour être sûr.
Un traitement supplémentaire est nécessaire pour gérer les nombres non positifs.
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());
}
Ma première version utilisait un StringBuilder
pour créer la chaîne à partir du tableau de caractères mais pour extraire la chaîne "du" StringBuilder
nécessite un appel à la méthode nommée ToString
. De toute évidence, cette méthode ne fait aucune conversion int en chaîne, ce qui pour moi est le sujet de cette question.
Mais pour prouver que vous pouvez créer une chaîne sans appeler ToString
, je suis passé à l'aide d'un constructeur string
que je supposerais également plus efficace que d'utiliser un StringBuilder
.
Et si ToString
sous quelque forme que ce soit est interdit, vous ne pouvez pas utiliser la concaténation de chaînes comme indiqué dans la documentation pour string.Concat
:
La méthode concatène arg0 et arg1 en appelant la méthode ToString sans paramètre de arg0 et arg1; il n'ajoute aucun délimiteur.
donc l'exécution de s += '1'
appellera '1'.ToString()
. Mais pour moi, ce n'est pas important. La partie importante est de savoir comment convertir un int en chaîne.
Viser une version plus courte et une qui utilise 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;
}
L'utilisation du constructeur new string(..., 1)
n'est qu'un moyen de satisfaire l'exigence de l'OP selon laquelle ToString
ne doit être appelé sur rien.
Voici mes points de vue à ce sujet en utilisant l'itération et la récursivité avec l'analyse du temps d'exécution.
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];
}
}
Voici l'analyse de l'exécution des deux méthodes par rapport à la fonction ToString()
standard sur mon ordinateur.
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
Les résultats indiquent que les méthodes d'itération et de récursivité s'exécutent 5,49 et 5,00 fois plus lentement que la méthode standard ToString()
.
Et voici le code que j'ai utilisé pour l'analyse:
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();
}
vous pouvez convertir n'importe quel chiffre en un caractère comme celui-ci
byte = (char)(byte)(digit+48)
Le nombre magique 48
est la valeur ASCII du caractère 0
et ils sont séquentiels dans la table ASCII donc vous pouvez simplement ajouter le chiffre pour obtenir la valeur correspondante dans la table ASCII. et vous pouvez obtenir la chiffres de l'entier de manière itérative à l'aide de l'opérateur de module %
Emprunter la structure générale du pswg que vous obtiendriez
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());
}
S'il s'agit de c ++, alors:
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);
}
Récursivité:
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);
}