数字をカスタム2Char basexに変換して戻るにはどうすればよいですか? (別名:Azure Tableプロパティ圧縮の方法)
-
03-10-2019 - |
質問
ヘックスで0からfまでカウントされる方法に似ていますが、「カウント」したい数字と文字の配列があります...そして、最大値に達したとき、私は「TENS」でもう一度始めたいと思います" 桁。
Azure Tableのストレージ効率を高め、PrimaryKeysをTinyに保つためにこれが必要です(したがって、Tinyurlで使用できます)。まず、これらの文字のみが文書化されているようにPropertyNameとして許可されていることを考えてください ここ. 。以下の配列では、各文字がAzureのソート方法に従って配置されます。
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"
};
私の目標は、2つの文字列/ASCII文字を使用して、文字列「00」から「ZZ」を小文字にカウントすることです。
C#を使用してこの概念にアプローチする最良の方法は何ですか?
- 配列は使用する正しいオブジェクトですか?
- 特定の文字(大文字の「Y」)を配列内の位置に関連付けるにはどうすればよいですか?
私はただこのアイデアを試しています。最初は良いもののように思えますが、このように物事をすることを検討する人は誰も見ていません。どう思いますか?
解決
あなたの質問は、実際に数値を2桁のベース62番号に変換することです。正の数を任意のベースに変換するためのコードの一般的なスニペットは次のとおりです。
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;
}
数字を文字にマッピングする必要があります。また、ルックアップテーブル、またはそれを行うための小さな関数が適切です。
さまざまな数字の数字を持つという追加機能に関する特定の問題については、このコードを書きます。
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;
}
このコードが変換されることに注意してください 0
の中へ 000
, 1
の中へ 001
など。しかし、それは実際にあなたが望むものだと思います。
変換するには、このコードを使用できます。
var n = 0;
for (var i = 0; i < number.Length; ++i)
n = n*digits.Length + digits.IndexOf(number[i]);
String.IndexOf()
コンバージョンを行うための最も効率的な方法ではありませんが、ほとんどの場合、問題ないはずです。
元の数値がベース62に保存できる最大数よりも大きい場合、変換は異なる数になります。ベース62の3桁の場合、これは元の数値が大きい場合に当てはまります zzz = 62^3 - 1 = 238327
.
他のヒント
配列の要素はすべて単一文字であるため、おそらくそれを文字の配列として宣言することができます。
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'
};
これで、すべてのセット全体を返す関数を簡単に書き込むことができます n- 目的の文字列長のCharacter文字列 n. 。私のバージョンは再帰的です。長い弦には遅すぎると思われる場合は、おそらく最適化できます。
public static IEnumerable<string> AzureStrings(int desiredLength)
{
if (desiredLength == 0)
return new[] { "" };
return AzureChars.SelectMany(ch => AzureStrings(desiredLength - 1)
.Select(str => ch + str));
}
これで、シーケンスのチャンクを使用して生成できます Skip
と 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());
これが何かを出力する前に最初の300の要素を計算するという事実にもかかわらず、それは私にとって十分な速さです。ここのこのクレイジーな計算でさえ、1秒未満かかります:
// Prints “5PkS, 5PkT, 5PkU, 5PkV, 5PkW, 5PkX, 5PkY, 5PkZ, 5Pka, 5Pkb”
Console.WriteLine(string.Join(", ", AzureStrings(4).Skip(1000000).Take(10)));
そのためにモジュラスを使用します(そして残りを取得します)
int i = AzureChars.Length;
int index = 62 //character to lookup;
string a = AzureChars[index % i];
charのインデックスを取得します:
int index = Array.IndexOf(AzureChars, "Y");
お気に入り:
string text = "YY";
int index1 = Array.IndexOf(AzureChars, text[1].ToString());
int index2 = Array.IndexOf(AzureChars, text[0].ToString());
おそらく、代わりにチャラレイ(char [])を使用するか、次のような長い文字列を使用する必要があります。
static string AzureChars= "012456789.....qrstuvwxyz";
それを明確にするためにすべて一緒に:
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 };
}
}
入力アルファが常に2桁であり、結果は常に3720未満であることを提供する