2

类似于在十六进制中从 0 计数到 F 的方式,我有一个数字和字母数组,我想从中“计数”......当我达到最大值时,我想在“十进制”中重新开始“ 柱子。

我需要这个来提高 Azure Table 中的存储效率,并保持我的 PrimaryKeys 很小(所以我可以在 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”)与其在数组中的位置相关联?

我只是在试验这个想法。乍一看好像还不错,但没见过有人考虑这样做。你怎么看?

4

3 回答 3

3

您的问题实际上是关于将数字转换为两位数的 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;
}

请注意,此代码将转换0000, 1into001等,但我认为这实际上是您想要的。

要转换回来,您可以使用以下代码:

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

于 2010-09-18T08:53:39.320 回答
2

由于数组的元素都是单个字符,因此您可以将其声明为字符数组:

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的所有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现在我们可以使用and生成序列的任何块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 个元素,但它对我来说已经足够快了。即使是这个疯狂的计算也需要不到一秒钟的时间:

// Prints “5PkS, 5PkT, 5PkU, 5PkV, 5PkW, 5PkX, 5PkY, 5PkZ, 5Pka, 5Pkb”
Console.WriteLine(string.Join(", ", AzureStrings(4).Skip(1000000).Take(10)));
于 2010-09-18T08:38:26.987 回答
2

使用模数(并获得余数)

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

获取一个字符的索引:

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

也许您应该改用 CharArray (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 };
         }
    }

假设输入 alpha 始终为两位数且结果始终小于 3720

于 2010-09-18T08:28:41.463 回答