排序格式不正确



我有一个字符串数组,它包含像这样的文件名

 1.Script_DBScript_03122014

我想对这个数组进行排序,所以我写了以下代码:

Array.Sort(SQLScripts);

但排序后的数组是这样生成的:

 1.Script_DBScript(otherdetails)_03122014
 10.Script_DBScript(otherdetails)_03122014
 11.Script_DBScript(otherdetails)_03122014
 12.Script_DBScript(otherdetails)_03122014
 ...
 2.Script_DBScript(otherdetails)_03122014
 20.Script_DBScript(otherdetails)_03122014
 21.Script_DBScript(otherdetails)_03122014
 22.Script_DBScript(otherdetails)_03122014
 ... so on

如何获得以下形式的阵列

 1.Script_DBScript(otherdetails)_03122014
 2.Script_DBScript(otherdetails)_03122014
 3.Script_DBScript(otherdetails)_03122014
 4.Script_DBScript(otherdetails)_03122014
 5.Script_DBScript(otherdetails)_03122014
 ...
 50.Script_DBScript(otherdetails)_03122014

编辑:从目录中检索文件名的代码:

String[] SQLScripts = Directory.GetFiles(txtPath.Text, "*.sql");

您得到的结果是非常常见的字符串排序。您需要的是数字(或数字(排序。

在这种情况下,您可能需要解析字符串,从第一个点的左侧提取数字,使用int.Parse("string containing a number")等方法,然后按整数排序。

我会这样做,但我不建议在不了解你做什么的情况下复制粘贴我的代码:

SQLScripts = SQLScripts
    .OrderBy(T => int.Parse(T.Split('.')[0]))
    .ToArray();

您需要所谓的"自然排序顺序"。

实际上,有一个名为StrCmpLogicalW()的本机Windows API比较器,您可以使用它来实现这一点,通过p/Invoke调用它。

您可以使用它来编写一个通用字符串比较器,然后将其传递给Array.Sort()。这在很多情况下都很有用,因此它是添加到类库的候选者。

下面是一个完整的可编译示例:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security;
namespace ConsoleApp1
{
    [SuppressUnmanagedCodeSecurity]
    internal static class NativeMethods
    {
        [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
        public static extern int StrCmpLogicalW(string psz1, string psz2);
    }
    public sealed class NaturalStringComparer: IComparer<string>
    {
        public int Compare(string a, string b)
        {
            return NativeMethods.StrCmpLogicalW(a, b);
        }
    }
    sealed class Program
    {
        void run()
        {
            string[] array =
            {
                "1.Script_DBScript_03122014",
                "10.Script_DBScript_03122014",
                "11.Script_DBScript_03122014",
                "12.Script_DBScript_03122014",
                "2.Script_DBScript_03122014",
                "20.Script_DBScript_03122014",
                "21.Script_DBScript_03122014",
                "22.Script_DBScript_03122014"
            };
            Array.Sort(array); // Sorts in the wrong order.
            foreach (var filename in array)
                Console.WriteLine(filename);
            Console.WriteLine("n");
            Array.Sort(array, new NaturalStringComparer()); // Sorts correctly.
            foreach (var filename in array)
                Console.WriteLine(filename);
        }
        static void Main(string[] args)
        {
            new Program().run();
        }
    }
}

然而,如果您只是更改字符串的格式,将前导零添加到所有数字部分,那么这一切都将变得不必要。

您必须按.分割字符串,并将数字部分解析为int,然后才能进行数字排序。

您可以使用LINQ:

SQLScripts = SQLScripts
  .Select(str =>  {
      string[] split = str.Split('.');
      string numberPart = split[0].Trim();
      int i;
      bool isNumber = int.TryParse(numberPart, out i);
      int? number = isNumber ? i : (int?)null;
      return new { str, split, numberPart, number };
  })
  .OrderByDescending(x => x.number.HasValue)
  .ThenBy(x => x.number)
  .Select(x => x.str)
  .ToArray();

说明:

此查询首先选择一个具有所有相关信息的匿名类型,然后按Nullable<int>.HasValue属性排序,该属性是一个布尔值,指示是否可以将第一个令牌解析为int。由于truefalse"高",我使用了OrderByDescending,因为我希望不可解析的字符串位于底部。

之后(ThenBy(,它将根据数字本身进行排序,以获得数字顺序,而不是字典顺序。最后一步是从匿名类型中选择字符串,并使用ToArray获得新的有序string[]

最新更新