.NET正确排序兼作串数字
我有正在显示的数据集,让我调出定制的.NET代码和我被困在一个排序问题的应用程序。我的数据集中的一列包含字符串和数字数据,我想按字母顺序排序字符串,并用数字排序数字。 我所能做的就是拿出分拣机正在处理的当前值,并返回一些内容。.NET正确排序兼作串数字
如果我的列表是{“-6”,“10”,“5”},我想从这些数字中按字母顺序排列字符串。我想出来的是把他们都肯定的,那么以零填充,这样的:
public object Evaluate(object currentValue)
{
//add 'a' to beginning of non-numbers, 'b' to beginning of numbers so that numbers come second
string sortOrder = "";
if(!currentValue.IsNumber)
sortOrder = "a" + currentValue;
else
{
sortOrder = "b"
double number = Double.Parse(currentValue);
//add Double.MaxValue to our number so that we 'hopefully' get rid of negative numbers, but don't go past Double.MaxValue
number += (Double.MaxValue/2)
//pad with zeros so that 5 comes before 10 alphabetically:
//"0000000005"
//"0000000010"
string paddedNumberString = padWithZeros(number.ToString())
//"b0000000005"
//"b0000000010"
sortOrder += paddedNumberString;
}
}
问题:
如果我只是返回号码,然后它们会按照字母顺序排序和10会前5名,我甚至不知道负数会发生什么。
解决方案?:
我想到的一件事是试图从双打(8字节)转换为无符号长整型(8字节)。这将消除负数,因为它们将从0开始。但是10之前的问题仍然存在。对于这一点,也许垫0或东西...
看起来这应该是可能的,但我今天的愚蠢和可以不聪明。
示例数据:
'猫'
'4'
'5.4'
'狗'
'-400'
'土豚'
'12 .23.34.54'
“我一句”
'0'
应该被选到:
'12 .23.34.54'
'土豚'
'猫'
'狗'
'我的一句话'
'-400'
'0'
'4'
'5.4'
我怀疑你的东西叫做“自然排序顺序”后是。 Attwood上有个帖子:http://www.codinghorror.com/blog/2007/12/sorting-for-humans-natural-sort-order.html
这篇文章中有几个实现的例子。
到目前为止,您是最接近的。如果没有人发布算法,我会自己做更多的研究。 – MStodd 2012-02-10 17:45:30
@MStodd:如果这是你想要的,你可以看看我对另一个问题的回答:http://stackoverflow.com/a/7205788/98607 – 2012-02-10 17:55:34
不是很有效的,但是一个简单的比较算法,首先在数字和非数字之间进行分隔,然后在它们之间进行分类就可以工作 - 见下面的代码。该inneficiency来自于事实,我们会做字符串双变换了好几次,所以你可以做的数字(即存放在List<double?>
其双值)的预处理然后使用这些,而不是总在做解析。
public class StackOverflow_9231493
{
public static void Test()
{
List<string> list = new List<string>
{
"cat",
"4",
"5.4",
"dog",
"-400",
"aardvark",
"12.23.34.54",
"i am a sentence",
"0" ,
};
list.Sort(new Comparison<string>(delegate(string s1, string s2)
{
double d1, d2;
bool isNumber1, isNumber2;
isNumber1 = double.TryParse(s1, out d1);
isNumber2 = double.TryParse(s2, out d2);
if (isNumber1 != isNumber2)
{
return isNumber2 ? -1 : 1;
}
else if (!isNumber1)
{
return s1.CompareTo(s2);
}
else
{
return Math.Sign(d1 - d2);
}
}));
Console.WriteLine(string.Join("\n", list));
}
}
更新基于意见:
如果你只想返回的东西,而不直接使用的比较器,就可以使用相同的逻辑,但是它知道一个类型包装的数值怎么办如你所愿,如下图所示。
public class StackOverflow_9231493
{
public class Wrapper : IComparable<Wrapper>
{
internal string value;
private double? dbl;
public Wrapper(string value)
{
if (value == null) throw new ArgumentNullException("value");
this.value = value;
double temp;
if (double.TryParse(value, out temp))
{
dbl = temp;
}
}
public int CompareTo(Wrapper other)
{
if (other == null) return -1;
if (this.dbl.HasValue != other.dbl.HasValue)
{
return other.dbl.HasValue ? -1 : 1;
}
else if (!this.dbl.HasValue)
{
return this.value.CompareTo(other.value);
}
else
{
return Math.Sign(this.dbl.Value - other.dbl.Value);
}
}
}
public static void Test()
{
List<string> list = new List<string>
{
"cat",
"4",
"5.4",
"dog",
"-400",
"aardvark",
"12.23.34.54",
"i am a sentence",
"0" ,
};
List<Wrapper> list2 = list.Select(x => new Wrapper(x)).ToList();
list2.Sort();
Console.WriteLine(string.Join("\n", list2.Select(w => w.value)));
}
}
Downvoter,谨慎评论为什么? – carlosfigueira 2012-02-10 17:55:25
不能使用比较。看到描述 – MStodd 2012-02-10 18:03:13
看起来像每个人都downvoted。这真的很合适吗?也许他们确实符合downvote箭头上的“这个答案无用”标签,但是直到最近的编辑,我们甚至不知道我们正在实现的函数的签名。 – BACON 2012-02-10 18:09:55
我假设你的数据类型string
,而不是object
的。以下函数可以用Comparison<string>
delegate调用。
static int CompareTo(string string1, string string2)
{
double double1, double2;
// Add null checks here if necessary...
if (double.TryParse(string1, out double1))
{
if (double.TryParse(string2, out double2))
{
// string1 and string2 are both doubles
return double1.CompareTo(double2);
}
else
{
// string1 is a double and string2 is text; string2 sorts first
return 1;
}
}
else if (double.TryParse(string2, out double2))
{
// string1 is text and string2 is a double; string1 sorts first
return -1;
}
else
{
// string1 and string2 are both text
return string1.CompareTo(string2);
}
}
你可以这样测试:
static void Main(string[] args)
{
var list = new List<string>() {
"cat",
"4",
"5.4",
"dog",
"-400",
"aardvark",
"12.23.34.54",
"i am a sentence",
"0"
};
list.Sort(CompareTo);
foreach (var item in list)
Console.WriteLine(item);
}
无法使用比较。希望我的编辑能够让目标更清晰 – MStodd 2012-02-10 18:31:54
我要给你一个解决方案,但它需要一个任意的,固定的最大字符串大小,但需要对组
首先没有其他的信息,如下定义自定义字符集:
public class CustomChar
{
public static readonly int Base;
public static readonly int BitsPerChar;
public char Original { get; private set; }
public int Target { get; private set; }
private static readonly Dictionary<char, CustomChar> Translation;
private static void DefineOrderedCharSet(string charset)
{
foreach (var t in charset)
{
new CustomChar(t);
}
}
static CustomChar()
{
Translation = new Dictionary<char, CustomChar>();
DefineOrderedCharSet(",-.aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ");
BitsPerChar = (int)Math.Ceiling(Math.Log(Translation.Count, 2));
Base = (int) Math.Pow(2, BitsPerChar);
}
private CustomChar(char original)
{
Original = original;
if(Translation.Count > 0)
{
Target = Translation.Max(x => x.Value.Target) + 1;
}
else
{
Target = 0;
}
Translation[original] = this;
}
public static CustomChar Parse(char original)
{
return Translation[original];
}
}
然后定义的构建体,用于处理从字符串转换为System.Numeric.BigInteger如下
public class CustomString
{
public string String { get; private set; }
public BigInteger Result { get; private set; }
public const int MaxChars = 600000;
public CustomString(string source)
{
String = source;
Result = 0;
for (var i = 0; i < String.Length; i++)
{
var character = CustomChar.Parse(String[i]);
Result |= (BigInteger)character.Target << (CustomChar.BitsPerChar * (MaxChars - i - 1));
}
double doubleValue;
if (!double.TryParse(source, out doubleValue))
{
return;
}
Result = new BigInteger(0x7F) << (MaxChars * CustomChar.BitsPerChar);
var shifted = (BigInteger)(doubleValue * Math.Pow(2, 32));
Result += shifted;
}
public static implicit operator CustomString(string source)
{
return new CustomString(source);
}
}
通知的构造函数为CustomString
˚F inds加倍并扩充它们的BigInteger
表示以组织数值排序的事物。
这是一个相当快扔在一起,但得到从测试你的描述输出:
class Program
{
public static string[] Sort(params CustomString[] strings)
{
return strings.OrderBy(x => x.Result).Select(x => x.String).ToArray();
}
static void Main()
{
var result = Sort(
"cat",
"4",
"5.4",
"dog",
"-400",
"aardvark",
"12.23.34.54",
"i am a sentence",
"0");
foreach (var str in result)
{
Console.WriteLine(str);
}
Console.ReadLine();
}
}
你能举些例子值此列?它们只是附加了双精度的文本吗? – BACON 2012-02-10 16:57:46
这里可以发送比较器吗? http://msdn.microsoft.com/en-us/library/cfttsh47.aspx – jrsconfitto 2012-02-10 17:07:14
当您只有一个值时,比较函数不起作用。我可以从分类器当前正在评估的值中返回一个字符串。我会在我的描述中更加清楚 – MStodd 2012-02-10 17:31:31