.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'

+0

你能举些例子值此列?它们只是附加了双精度的文本吗? – BACON 2012-02-10 16:57:46

+0

这里可以发送比较器吗? http://msdn.microsoft.com/en-us/library/cfttsh47.aspx – jrsconfitto 2012-02-10 17:07:14

+0

当您只有一个值时,比较函数不起作用。我可以从分类器当前正在评估的值中返回一个字符串。我会在我的描述中更加清楚 – MStodd 2012-02-10 17:31:31

我怀疑你的东西叫做“自然排序顺序”后是。 Attwood上有个帖子:http://www.codinghorror.com/blog/2007/12/sorting-for-humans-natural-sort-order.html

这篇文章中有几个实现的例子。

+0

到目前为止,您是最接近的。如果没有人发布算法,我会自己做更多的研究。 – MStodd 2012-02-10 17:45:30

+0

@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))); 
    } 
} 
+0

Downvoter,谨慎评论为什么? – carlosfigueira 2012-02-10 17:55:25

+0

不能使用比较。看到描述 – MStodd 2012-02-10 18:03:13

+1

看起来像每个人都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); 
} 
+0

无法使用比较。希望我的编辑能够让目标更清晰 – 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(); 
    } 
}