Wie konvertiere ich eine Nummer zu einem benutzerdefinierten 2char BaseX und zurück? (Aka: Wie Azure Table Eigenschaft Kompression tun)

StackOverflow https://stackoverflow.com/questions/3740865

Frage

ähnlich wie in, wie man von 0 bis F in Hex zählen würde, habe ich eine Reihe von Zahlen und Buchstaben Ich mag „count“ aus ... und wenn ich den maximalen Wert treffen, möchte ich alles wieder von vorn anfangen in die "Zehner" Spalte.

Ich brauche diese Speichereffizienz in Azure Tabelle zu erhöhen, und meinen PrimaryKeys winzig zu halten (so ich sie in einem tinyURL verwenden kann). Betrachten wir zunächst, dass nur diese Zeichen als Eigenschaftsname zulässig sind, wie dokumentiert hier . In der Anordnung unten wird jedes Zeichen positioniert je nachdem, wie es Azure sortieren werden.

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

Mein Ziel ist es 2 string / ASCII-Zeichen zu verwenden, aus der Zeichenfolge "00" zu zählen, in Kleinbuchstabe "zz".

Was ist der beste Weg, um dieses Konzept zu nähern mit C #?
- ist ein Array das richtige Objekt zu verwenden
? - Wie werde ich ein bestimmtes Zeichen (Großbuchstaben ‚Y‘) assoziieren damit seine Position im Array

Ich experimentiere gerade mit dieser Idee. Auf den ersten Pinsel scheint es wie eine gute, aber ich habe niemanden, Dinge zu tun auf diese Weise betrachten gesehen. Was denken Sie?

War es hilfreich?

Lösung

Sie Frage ist wirklich eine Zahl in einer zweistelligen Zahl Basis 62 konvertieren. Hier ist ein allgemeiner Code-Snippet für eine positive Zahl in eine beliebige Basis Umwandlung:

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

Sie haben die Ziffern in Zeichen abzubilden und eine Lookup-Tabelle oder eine kleine Funktion dafür, dass geeignet ist.

Für Ihr spezielles Problem mit der zusätzlichen Funktion eine variable Anzahl von Ziffern, das würde ich diesen Code schreiben:

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

Beachten Sie, dass dieser Code 0 in 000, 1 in 001 usw. konvertieren, aber ich denke, das ist eigentlich das, was Sie wollen.

So konvertieren zurück Sie können diesen Code verwenden:

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

Die String.IndexOf() ist nicht der effizienteste Weg, um die Konvertierung zu tun, aber in den meisten Fällen sollte in Ordnung sein.

Beachten Sie, dass, wenn Ihre ursprüngliche Zahl größer ist als die größte Zahl, die in Ihrer Basis 62 Nummer gespeichert wird, kann die Umwandlung zurück in einer anderen Zahl führen wird. Für 3 Ziffern in der Basis 62, das ist wahr, wenn die ursprüngliche Zahl größer als oder gleich zzz = 62^3 - 1 = 238327.

Andere Tipps

Da die Elemente Ihres Arrays alle einzelnen Zeichen sind, können Sie wahrscheinlich erklären es als ein Array von Zeichen:

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

Nun können Sie eine Funktion schreiben, dass die Rendite der gesamten Menge aller n -Charakter Strings für jede beliebige Stringlänge n . Meine Version ist rekursiv; wenn Sie feststellen, dass es für längere Strings zu langsam ist, können Sie wahrscheinlich optimieren:

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

Jetzt können wir jedes Stück der Sequenz mit Skip und Take erzeugen:

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

Trotz der Tatsache, dass dies die ersten 300 Elemente berechnet, bevor etwas ausgeben, ist es Art und Weise schnell genug für mich. Auch diese verrückte Berechnung hier dauert weniger als eine Sekunde:

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

verwendet den Modul für die (und den Rest erhalten)

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

Ermittelt den Index eines char:

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

wie:

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

sollten Sie vielleicht einen CharArray (char []) verwenden, anstatt, oder einfach nur eine lange Zeichenfolge wie:

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

alle zusammen, um es zu löschen:

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

vorausgesetzt, dass ein Eingang alpha ist immer zweistellig und das Ergebnis ist immer weniger als 3720

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top