按字典顺序对任何内容进行排序
Sort anything lexicographically
我有这段代码,我想是几年前在互联网上的某个地方找到的,但它不太管用。
目的是获取任何字符串并从中创建一个字符串,该字符串按字典顺序按大数字排序 - 因为这样可以通过从另一个更大的数字中减去该数字来实现反向(降序)排序。
private static BigInteger maxSort = new BigInteger(Encoding.Unicode.GetBytes("5335522543087813528200259404529154678271640415603227881439560533607051111046319775598721171814499900"));
public static string GetSortString(string str, bool descending)
{
var sortNumber = new BigInteger(Encoding.Unicode.GetBytes(str));
if (descending)
{
sortNumber = maxSort - sortNumber;
}
return "$SORT!" + sortNumber.ToString().PadLeft(100, '0') + ":" + str;
}
我需要这个的原因是因为我想用它在 Azure Table 存储中作为 RowKey 插入,这是在 Table 存储中排序的唯一方法。我需要对任何文本、任何数字和任何日期进行升序和降序排序。
任何人都可以看到代码的问题或有任何代码可以达到相同的目的吗?
这个问题是用 C# 标记的,但当然这不是语法问题,所以如果您在任何其他代码中有答案,那也很好。
例子
我想将任何字符串转换为按字典顺序正确排序的数字 - 因为如果它是数字,那么我可以将其反转并降序排序。
例如,如果我可以转换:
ABBA to 1234
Beatles to 3131
ZZ Top to 9584
然后这些数字将正确排序......而且,如果我从一个大数字中减去它们,我将能够反转排序顺序:
10000 - 1234 = 8766
10000 - 3131 = 6869
10000 - 9584 = 0416
当然,为了支持更长的文本输入,我需要从一个非常大的数字中减去它们,这就是为什么我使用非常大的BigInteger。
此代码的当前输出
ABBA: $SORT!0000000000000000000000018296156958359617:ABBA
Beatles: $SORT!0000000009111360792640460912278748069954:Beatles
ZZ TOP: $SORT!0000000000000096715522885596192519618650:ZZ TOP
如您所见,最长的文本获得最高的编号。我还尝试在输入 str
上立即添加填充,但这也无济于事。
回答
已接受的答案有效。对于降序排序,可以使用上面的“BigInteger”技巧。
可排序字符串的长度有一些限制。
这是最终代码:
private static BigInteger maxSort = new BigInteger(Encoding.Unicode.GetBytes("5335522543087813528200259404529154678271640415603227881439560533607051111046319775598721171814499900"));
public static string GetSortString(string str, bool descending)
{
BigInteger result = 0;
int maxLength = 42;
foreach (var c in str.ToCharArray())
{
result = result * 256 + c;
}
for (int i = str.Length; i < maxLength; i++)
{
result = result * 256;
}
if (descending)
{
result = maxSort - result;
}
return "$SORT!" + result;
}
如果您正在寻找一种方法来为任何字符串赋值,以便您可以根据数字对它们进行排序并获得与上述相同的结果,那么您做不到。原因是字符串没有任何长度限制。因为您总是可以将一个字符添加到一个字符串中,从而获得更大的数字,即使它应该具有较低的字典序值。
如果他们有长度限制,你可以这样做
伪代码
bignum res = 0;
maxLength = 42;
for (char c : string)
res = res * 256 + c
for (int i = string.length; i < maxLength; i++)
res = res *256
如果你想优化一下,最后一个循环可以是查找 table。如果你只使用 a-z,256 次可以减少到 26 或 32。