如何将System.Int64表示为可按词法排序的字符串
本文关键字:词法 排序 字符串 System Int64 表示 | 更新日期: 2023-09-27 18:25:28
我想将(64位)整数转换为词汇可排序的字符串(即,我可以使用String.Compare对结果字符串进行排序,并获得与直接比较原始值相同的顺序)。Jon Skeet在这里提供了替身的实现。我想对Int64做同样的事情(还有Int32、float、datetime、timespan,但我相信我可以从Int64做到这一点)。
如何将C#中的System.Int64表示为词汇可排序字符串
我喜欢链接的实现使用ASCII字符(它是十六进制编码的),因此即使不是严格意义上的可读性,也能模糊地呈现出来。
我正在寻找一种适用于Int64的所有有效正值和负值的方法。
这里有一个测试,适用于Jon Skeet的"EncodeDouble"实现,以及其中每个方法的实现。我的实现与关联问题没有变化,但提供了完整性。
[TestMethod]
public void LexicallySortRandomDoubles()
{
var r = new Random(15245);
for (int i = 0; i < 10000; ++i)
{
var bytes = new byte[16];
r.NextBytes(bytes);
var a = BitConverter.ToDouble(bytes, 0);
var b = BitConverter.ToDouble(bytes, 8);
// don't sort equal values, or nans.
if (double.IsInfinity(a) || double.IsNaN(a) || double.IsInfinity(b) || double.IsNaN(b)) continue;
var c = LexicallySortableValues.EncodeDouble(a);
var d = LexicallySortableValues.EncodeDouble(b);
// Comparison works
Assert.IsTrue(
a < b == System.String.Compare(c, d, System.StringComparison.InvariantCultureIgnoreCase) < 0,
string.Format("i={4}, a = {0}, b = {1}, c = {2}, d = {3}", a, b, c, d, i));
}
}
public static ulong DoubleToSortableULong(double d)
{
long ieee = System.BitConverter.DoubleToInt64Bits(d);
const ulong widezero = 0;
return ((ieee < 0) ? widezero : ((~widezero) >> 1)) ^ (ulong)~ieee;
}
public static double SortableULongToDobule(ulong lex)
{
const ulong widezero = 0;
long ieee = (long)(((0 <= (long)lex) ? widezero : ((~widezero) >> 1)) ^ ~lex);
return System.BitConverter.Int64BitsToDouble(ieee);
}
public static string EncodeDouble(double d)
{
ulong lex = DoubleToSortableULong(d);
return lex.ToString("X16");
}
public static double DecodeDouble(string s)
{
ulong lex = ulong.Parse(s, System.Globalization.NumberStyles.AllowHexSpecifier);
return SortableULongToDobule(lex);
}
为了处理Int64
的有符号性质,我建议您通过添加-Int64.MinValue
将有符号64位整数转换为无符号64位值。移位保留排序,并且选择移位值以确保结果始终可在UInt64
变量中表示。
然后用ToString("D20")
将格式设置为19位十进制数字。或使用ToString("X16")
将十六进制数字转换为十六进制数字。
执行这样的转换:
static UInt64 ShiftToUnsigned(Int64 sval)
{
unchecked
{
return (UInt64) (sval - Int64.MinValue);
}
}
然后转换为字符串可以是:
static string LexicallySortable(Int64 value)
{
return ShiftToUnsigned(value).ToString("X16");
}
然后这个程序
static void Main(string[] args)
{
Console.WriteLine(String.Compare(LexicallySortable(Int64.MinValue), LexicallySortable(-2)));
Console.WriteLine(String.Compare(LexicallySortable(-2), LexicallySortable(-1)));
Console.WriteLine(String.Compare(LexicallySortable(-1), LexicallySortable(0)));
Console.WriteLine(String.Compare(LexicallySortable(0), LexicallySortable(1)));
Console.WriteLine(String.Compare(LexicallySortable(1), LexicallySortable(Int64.MaxValue)));
Console.ReadLine();
}
根据需要输出一系列CCD_ 6值。