Come faccio a convertire un numero a una consuetudine 2char BaseX e ritorno? (Aka: come fare Azure Table compressione proprietà)
-
03-10-2019 - |
Domanda
Simile a come si potrebbe contare da 0 a F in esadecimale, ho una serie di numeri e lettere che voglio "contare" dal ... e quando ho colpito il valore massimo, voglio iniziare tutto da capo in la colonna "decine".
Ho bisogno di questo per aumentare l'efficienza dello storage in Azure Table, e per mantenere la mia PrimaryKeys minuscola (modo che io possa utilizzare in un tinyURL). In primo luogo ritengono che solo questi caratteri sono consentiti come propertyName, come documentato qui . Nella matrice di seguito, ogni carattere viene posizionato in base a come Azure risolverlo.
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"
};
Il mio obiettivo è quello di utilizzare i caratteri di stringa 2 / ASCII a contare dalla stringa "00" in minuscolo "zz".
Qual è il modo migliore per affrontare questo concetto utilizzando C #?
- è un array l'oggetto corretto da utilizzare
?
-? Come faccio associare un determinato carattere (maiuscolo 'Y'), con la sua posizione nella Matrice
Sono solo a sperimentare con questa idea. In un primo pennello sembra una buona, ma non ho visto nessuno prendere in considerazione fare le cose in questo modo. Cosa ne pensi?
Soluzione
Si domanda è in realtà sulla conversione di un numero in un due cifre di base 62 il numero. Ecco un frammento generale di codice per convertire un numero positivo in 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;
}
È necessario mappare le cifre in caratteri e una tabella di ricerca o una piccola funzione per fare che è adatto.
Per il vostro problema specifico con la funzione aggiuntiva di avere un numero variabile di cifre avrei scritto questo codice:
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;
}
Si noti che questo codice convertirà 0
in 000
, 1
in 001
ecc, ma credo che in realtà è ciò che si desidera.
Per convertire indietro è possibile utilizzare questo codice:
var n = 0;
for (var i = 0; i < number.Length; ++i)
n = n*digits.Length + digits.IndexOf(number[i]);
Il String.IndexOf()
non è il modo più efficace per fare la conversione, ma nella maggior parte dei casi dovrebbe essere OK.
Si noti che se il vostro numero originale è maggiore del numero più grande che possono essere memorizzati nel tuo numero di base 62 la parte posteriore di conversione si tradurrà in un numero diverso. Per 3 cifre in base 62, questo è vero se il numero originale è maggiore o uguale a zzz = 62^3 - 1 = 238327
.
Altri suggerimenti
Poiché gli elementi dell'array sono tutti i singoli caratteri, probabilmente si può dichiarare come un array di caratteri:
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'
};
Ora si può facilmente scrivere una funzione che restituisce l'intero set di tutti i n stringhe -CHARACTER per un certo periodo di stringa desiderata n . La mia versione è ricorsiva; se si scopre che è troppo lento per le stringhe piuttosto lunga, probabilmente si può ottimizzarla:
public static IEnumerable<string> AzureStrings(int desiredLength)
{
if (desiredLength == 0)
return new[] { "" };
return AzureChars.SelectMany(ch => AzureStrings(desiredLength - 1)
.Select(str => ch + str));
}
Ora siamo in grado di generare qualsiasi pezzo della sequenza usando Skip
e 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());
Nonostante il fatto che questo calcola i primi 300 elementi prima di emettere qualsiasi cosa, è modo abbastanza veloce per me. Anche questo calcolo folle qui richiede meno di un secondo:
// Prints “5PkS, 5PkT, 5PkU, 5PkV, 5PkW, 5PkX, 5PkY, 5PkZ, 5Pka, 5Pkb”
Console.WriteLine(string.Join(", ", AzureStrings(4).Skip(1000000).Take(10)));
utilizzare il modulo per questo (e ottenere il resto)
int i = AzureChars.Length;
int index = 62 //character to lookup;
string a = AzureChars[index % i];
Ottenere l'indice di un char:
int index = Array.IndexOf(AzureChars, "Y");
come:
string text = "YY";
int index1 = Array.IndexOf(AzureChars, text[1].ToString());
int index2 = Array.IndexOf(AzureChars, text[0].ToString());
forse si dovrebbe usare un CharArray (char []) invece, o semplicemente una lunga stringa come:
static string AzureChars= "012456789.....qrstuvwxyz";
tutti insieme per rendere chiaro:
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 };
}
}
condizione che un'alfa ingresso è sempre due cifre e il risultato è sempre minore di 3720