通过创建单个值按两个整数字段(一个 desc 和一个 asc)排序

Sorting by two integer fields, one desc and one asc, by creating a single value

我收集了以下对象:

public class TestObject
{
    public string Id { get; set;}
    public int Value1 { get; set; }
    public int Value2 { get; set; }
}

如您所见,它包含两个整数值。我想按 Value1 降序然后 Value2 升序对集合进行排序。

为清楚起见,在 SQL:

SELECT   *
FROM     testobjects
ORDER BY Value1 DESC
ORDER BY Value2 ASC

或者如果您愿意,在 c# linq 中:

testObjects
    .OrderByDescending(o => o.Value1)
    .ThenBy(o => o.Value2);

但问题是...我需要通过将两个数字组合成一个数值来完成此操作,然后可以对其进行排序。 (为什么?CosmosDB,但这不是重点!)

我突然想到,如果我们采用 (Value1 x 1000) - Value2 然后按降序排列,前提是 Value2 不超过我们任意的 1000 那么这可能会起作用。

会吗?当然有更好的方法...?

SxS' 的字典序中的枚举,其中 S 是 int 的有序值集,S' 是 int 的值集,顺序相反,由下式给出

w((x,y)) = (x + min_S)·|S| + (max_S - y)

其中x,y是int,min_S是最小的int,max_S是最大的int

下面是如何比较 Value1Value2,两者都是升序的。

  1. Value1放入一个64位整数的高32位。
  2. 翻转Value2上的高位(符号位),并将其放入低32位。

例如:

public static long getKey(int val1, int val2)
{
    long key = val1;
    key <<= 32;
    uint flipped = (uint)val2 ^ 0x80000000;
    key |= flipped;
    return key;
}

这将对 Value1Value2 进行升序排序。但是您希望 Value1 降序排序。所以只需翻转第一个值中的所有位。将第一行更改为:

long key = (uint)~val1;

那么这是如何工作的呢?我将使用范围为 -8 .. 7 的 4 位有符号整数进行解释。高位是符号位。所以从低到高的表示是:

                               Bit     Unsigned
    Binary  Inverted  Value  Flipped   Value
-8  1000      0111     7      0000      0
-7  1001      0110     6      0001      1
-6  1010      0101     5      0010      2
-5  1011      0100     4      0011      3
-4  1100      0011     3      0100      4
-3  1101      0010     2      0101      5
-2  1110      0001     1      0110      6
-1  1111      0000     0      0111      7
 0  0000      1111    -1      1000      8
 1  0001      1110    -2      1001      9
 2  0010      1101    -3      1010     10
 3  0011      1100    -4      1011     11
 4  0100      1011    -5      1100     12
 5  0101      1010    -6      1101     13
 6  0110      1001    -7      1110     14
 7  0111      1000    -8      1111     15

第一列是数字。下一列显示二进制补码表示。 "Inverted" 列显示反转位的二进制结果,下一列显示表示的十进制值。这是我们放置在结果高位的值。如您所见,数字已经交换位置,最低 (-8) 变为最高。这将为我们提供降序排序的值。

除非高位相等,否则低位无关紧要。 "Bit Flipped" 列显示了翻转高位后值的二进制表示。这样做是将数字 -8 到 7 映射到无符号范围 0 到 15,从而确保正确比较数字的低位。