【问题标题】:Sort anything lexicographically按字典顺序对任何内容进行排序
【发布时间】:2021-09-18 08:56:28
【问题描述】:

我有这个代码,我想我是几年前在互联网上的某个地方找到的,但它并不完全有效。

目的是获取任何字符串,并从中创建一个按字典顺序按大数字排序的字符串 - 因为可以通过从另一个更大的数字中减去该数字来实现逆(降序)排序。

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

我需要这个的原因是因为我想用它作为 RowKey 插入到 Azure 表存储中,这是在表存储中排序的唯一方法。我需要对任何文本、任何数字和任何日期进行排序,包括升序和降序。

任何人都可以看到代码的问题或有任何用于相同目的的代码吗?

这个问题是用 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;
}

【问题讨论】:

  • 对不起,“按大数按字典顺序排序”是什么意思?能否请您提供一些示例?例如,"1443235" 的期望结果是什么,为什么?不是"1233445"吗?
  • 是的,我会用一个例子来更新这个问题。谢谢。
  • 我仍然不明白需要将它们映射到整数 - 在 C# 中已经有很多方法可以按字典顺序(按升序或降序)对字符串进行排序,RowKey 属性是,如你说,文本
  • 请分享!我希望我忽略了一些明显的东西。我不需要在 C# 中对事物进行排序,我需要创建已经正确排序的字符串,以便按照我想要的顺序将它们从表存储中取出。
  • @NielsBrinch:您是否跳过这些圈子只是为了能够按降序对某些字符串进行排序? - 因为有更简单的方法可以做到这一点。

标签: c# algorithm sorting azure-table-storage


【解决方案1】:

如果您正在寻找一种为任何字符串赋值的方法,以便您可以根据数字对它们进行相应的排序并获得与上述相同的结果,那么您做不到。原因是字符串没有任何长度限制。因为您始终可以将 char 添加到字符串中,从而获得更大的数字,即使它应该具有较低的字典值。

如果他们有长度限制,你可以这样做

伪代码

bignum res = 0;
maxLength = 42;
for (char c : string)
  res = res * 256 + c
for (int i = string.length; i < maxLength; i++)
  res = res *256

如果你想稍微优化一下,最后一个循环可以是一个查找表。如果您只使用 a-z,则 256 次可以减少到 26 或 32。

【讨论】:

  • 是的,我不是在寻找一种排序方式。查看您的伪代码。我对字符串的长度限制感到满意,并且在我自己的尝试中也限制了 100 个字符。你认为这会奏效 - 反过来也会奏效?
  • 您的伪代码中的 * 是否意味着乘数?询问是因为某些语言将其用作某种参考指标。
  • 我应该对太短的字符串做些什么吗?用 0 填充它们?之前还是之后?
  • @NielsBrinch 没有第二个循环负责。嗯,倒车时应该是 256-c。
  • 该代码适用于升序,但不适用于降序。但也许我不清楚它应该去哪里 256 - c。即使它必须在第一个循环中,因为那是唯一有 c 的地方。
猜你喜欢
  • 2011-03-01
  • 1970-01-01
  • 2012-05-30
  • 1970-01-01
  • 1970-01-01
  • 2020-09-26
  • 2018-01-27
  • 1970-01-01
相关资源
最近更新 更多