2010-09-18 18 views
2

Similaire à comment on compterait de 0 à F en hexadécimal, j'ai un tableau de nombres et de lettres que je veux "compter" à partir de ... et quand je frappe au maximum valeur, je veux tout recommencer dans la colonne des "dizaines".Comment est-ce que je convertis un nombre à un 2char BaseX et arrière de coutume? (aka: Comment faire la compression de la propriété Azure Table)

J'ai besoin de cela pour augmenter l'efficacité du stockage dans Azure Table, et pour garder mes PrimaryKeys minuscules (donc je peux les utiliser dans un tinyURL). Tout d'abord, considérez que seuls ces caractères sont autorisés en tant que propriété, comme documenté here. Dans le tableau ci-dessous, chaque caractère est positionné en fonction de la manière dont Azure le triera.

public static string[] AzureChars = new string[] 
    { 
     "0","1","2","3","4","5","6","7","8","9","A", 
     "B","C","D","E","F","G","H","I", 
     "J","K","L","M","N","O","P","Q", 
     "R","S","T","U","V","W","X","Y", 
     "Z","a","b","c","d","e","f","g", 
     "h","i","j","k","l","m","n","o", 
     "p","q","r","s","t","u","v","w", 
     "x","y","z"  
    }; 

Mon but est d'utiliser 2 caractères ASCII pour compter de la chaîne «00» à la minuscule «zz».

Quelle est la meilleure façon d'aborder ce concept en utilisant C#?
- Un tableau est-il l'objet correct à utiliser?
- Comment associer un caractère donné (majuscule 'Y') à sa position dans le tableau?

Je suis juste en train d'expérimenter avec cette idée. Au premier coup d'oeil, ça semble être une bonne chose, mais je n'ai vu personne envisager de faire les choses de cette façon. Qu'est-ce que tu penses?

+0

... laissez-moi savoir s'il y a une meilleure façon de formuler ma question ... – LamonteCristo

Répondre

3

Votre question est vraiment de convertir un nombre en un nombre de base de deux chiffres 62. Voici un extrait général de code pour la conversion d'un nombre positif dans une base arbitraire:

var n = 1234; 
var baseNumber = 62; 
var numberOfDigits = 2; 
var digits = new Int32[numberOfDigits]; 
for (var i = 0; i < digits.Length; i += 1) { 
    digits[i] = n%baseNumber; 
    n /= baseNumber; 
} 

Vous devez mapper les chiffres en caractères et une table de consultation ou une petite fonction pour faire cela est approprié.

Pour votre problème spécifique avec la fonction supplémentaire d'avoir un nombre variable de chiffres j'écrire ce code:

var n = 123456; 
var digitCount = 3; 
var digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 
var number = String.Empty; 
for (var i = 0; i < digitCount; ++i) { 
    number = digits[n%digits.Length] + number; 
    n /= digits.Length; 
} 

Notez que ce code vous permet de convertir 0 en 000, 1 en 001 etc., mais je pense c'est en fait ce que vous voulez.

Pour reconvertir, vous pouvez utiliser ce code:

var n = 0; 
for (var i = 0; i < number.Length; ++i) 
    n = n*digits.Length + digits.IndexOf(number[i]); 

Le String.IndexOf() n'est pas la façon la plus efficace de faire la conversion, mais dans la plupart des cas devrait être OK.

Notez que si votre numéro d'origine est plus grand que le plus grand nombre qui peut être stocké dans votre base 62 numéro de la conversion arrière se traduira par un nombre différent. Pour 3 chiffres dans la base 62, ceci est vrai si le nombre d'origine est supérieur ou égal à zzz = 62^3 - 1 = 238327.

+0

Tout simplement fantastique! – LamonteCristo

2

utiliser le module pour cela (et obtenir le reste)

 int i = AzureChars.Length; 
     int index = 62 //character to lookup; 
     string a = AzureChars[index % i]; 

l'index de char:

 int index = Array.IndexOf(AzureChars, "Y"); 

comme:

 string text = "YY"; 
     int index1 = Array.IndexOf(AzureChars, text[1].ToString()); 
     int index2 = Array.IndexOf(AzureChars, text[0].ToString()); 

peut-être vous devriez utiliser un CharArray (char []) à la place, ou juste une longue chaîne comme:

static string AzureChars= "012456789.....qrstuvwxyz"; 

tous ensemble pour préciser:

static void Main(string[] args) 
    { 
     char[] b = AzureCharConverter.ToCharArray(522); 
     int i = AzureCharConverter.ToInteger(b); 
    } 


    public static class AzureCharConverter 
    { 
     private static readonly string _azureChars 
     = "012456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 

     public static int ToInteger(string chars) 
     { 
       int l = _azureChars.IndexOf(chars[0]); 
       int r = _azureChars.IndexOf(chars[1]); 
       return (l * _azureChars.Length) + r; 
     } 


     public static char[] ToCharArray(int value) 
     { 
        char l = _azureChars[value/_azureChars.Length]; 
        char r = _azureChars[value % _azureChars.Length]; 
        return new char[] { l, r }; 
     } 
    } 

prévoir qu'une alpha d'entrée est toujours deux chiffres et le résultat est toujours moindre que 3720

+0

Puisque l'OP veut deux chiffres, 'a' devrait être une combinaison de' AzureChars [index/i] + AzureChars [index % i] '. Une modification analogue doit être faite pour aller chercher l'index (index du premier caractère * 'i' + index du deuxième caractère). – stakx

+0

devinez c'est --finally-- fait ... –

+0

11 révisions révèlent beaucoup sur le processus de pensée! Merci Caspar! – LamonteCristo

2

Puisque les éléments de votre tableau sont tous des caractères simples , vous pouvez probablement le déclarer comme un tableau de caractères:

public static char[] AzureChars = new char[] 
{ 
    '0', '1', '2', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 
    'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 
    'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 
    'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 
    'v', 'w', 'x', 'y', 'z'  
}; 

maintenant, vous pouvez facilement écrire une fonction qui retourne l'ensemble de tous n - chaînes de caractères pour toute longueur de chaîne souhaitée n. Ma version est récursive; si vous trouvez qu'il est trop lent pour les chaînes oblongues, vous pouvez probablement l'optimiser:

public static IEnumerable<string> AzureStrings(int desiredLength) 
{ 
    if (desiredLength == 0) 
     return new[] { "" }; 
    return AzureChars.SelectMany(ch => AzureStrings(desiredLength - 1) 
             .Select(str => ch + str)); 
} 

Maintenant, nous pouvons générer une partie de la séquence en utilisant Skip et Take:

// Prints “5v, 5w, 5x, 5y, 5z, 60, 61, 62, 64, 65” 
Console.WriteLine(string.Join(", ", AzureStrings(2).Skip(300).Take(10))); 
// Prints “3721” 
Console.WriteLine(AzureStrings(2).Count()); 

Malgré le fait que cette calcule les 300 premiers éléments avant de sortir quoi que ce soit, c'est assez rapide pour moi.Même ce calcul fou prend ici moins d'une seconde:

// Prints “5PkS, 5PkT, 5PkU, 5PkV, 5PkW, 5PkX, 5PkY, 5PkZ, 5Pka, 5Pkb” 
Console.WriteLine(string.Join(", ", AzureStrings(4).Skip(1000000).Take(10))); 
+0

+1 pour une mise en œuvre impressionnante/créative ... mais comment puis-je prendre une chaîne et l'incrémenter? (aka convertir la chaîne en ce qui va dans Skip)? – LamonteCristo

+0

'AzureStrings (str.Length) .SkipWhile (s => s! = Str) .Skip (1) .Take (n)', mais être averti que cela aussi est une mise en œuvre créative, mais inefficace :) – Timwi

+0

En outre, comment puis-je aller de la chaîne à int? – LamonteCristo