¿Cómo se convierte un número a una costumbre 2char BaseX y la espalda? (Aka: Cómo hacer Azure Tabla compresión de la propiedad)

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

Pregunta

Similar en cómo se podría contar de 0 a F en Hex, tengo una serie de números y letras que quiero "contar" de ... y cuando golpeo el valor máximo, quiero empezar todo de nuevo en la "decenas" columna.

Necesito esto para aumentar la eficiencia del almacenamiento de Azure tabla, y para mantener mis PrimaryKeys pequeña (para que pueda usarlos en un TinyURL). En primer lugar consideran que sólo se permiten estos personajes como nombrePropiedad, tal como se documenta aquí . En la matriz a continuación, cada carácter se coloca de acuerdo a cómo Azure clasificará ella.

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

Mi objetivo es utilizar caracteres de 2 cuerdas / ASCII a contar desde la cadena "00" en minúsculas "zz".

¿Cuál es la mejor manera de acercarse a este concepto utilizando C #?
- es una matriz del objeto correcto utilizar
? - ¿Cómo voy a asociar un determinado carácter (mayúsculas 'Y') con su posición en el array

Estoy experimentando con esta idea. En primer cepillo parece una buena idea, pero no he visto a nadie considere hacer las cosas de esta manera. ¿Qué opinas?

¿Fue útil?

Solución

pregunta es realmente acerca de la conversión de un número en un número de dos dígitos de base 62. Aquí hay un fragmento general de código para la conversión de un número positivo en una base arbitraria:

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

Se tiene que asignar los dígitos en caracteres y una tabla de consulta o una pequeña función para hacerlo es adecuado.

Para su problema específico con la característica adicional de tener un número variable de dígitos que iba a escribir este código:

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

Tenga en cuenta que este código se convertirá en 0 000, 1 en 001 etc., pero creo que es en realidad lo que quiere.

Para convertir de nuevo se puede utilizar este código:

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

El String.IndexOf() no es la forma más eficiente de hacer la conversión, pero en la mayoría de los casos debería estar bien.

Tenga en cuenta que si su número original es mayor que el número más grande que puede ser almacenada en su número de base 62 la parte posterior conversión se traducirá en un número diferente. Para 3 dígitos en base 62, esto es cierto si el número original es mayor que o igual a zzz = 62^3 - 1 = 238327.

Otros consejos

Dado que los elementos de la matriz son todos los caracteres individuales, es probable que pueda declarar como una matriz de caracteres:

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

Ahora se puede escribir fácilmente una función que devuelve todo el conjunto de todos los n cadenas -character para cualquier longitud de cadena deseada n . Mi versión es recursiva; si encuentra que es demasiado lento para las cadenas bastante largas, es probable que pueda optimizarlo:

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

Ahora podemos generar cualquier parte de la secuencia utilizando Skip y 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());

A pesar de que esta computa los primeros 300 elementos antes de dar salida nada, que es la forma lo suficientemente rápido para mí. Incluso este cálculo loco aquí tarda menos de un segundo:

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

utilizar el módulo para que (y conseguir el resto)

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

Obtener el índice de un carácter:

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

como:

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

tal vez debería utilizar un CharArray (char []) en lugar, o simplemente una larga cadena como:

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

todos juntos para que quede claro:

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

siempre que un alfa de entrada es siempre dos dígitos y el resultado es siempre menor que 3720

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top