排序格式不正确

时间:2014-03-12 08:51:40

标签: c# arrays

我有一个String数组,其中包含

等文件名
 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");

3 个答案:

答案 0 :(得分:3)

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

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

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

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

答案 1 :(得分:3)

你需要所谓的“自然排序”。

实际上有一个名为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();
        }
    }
}

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

答案 2 :(得分:2)

您必须将字符串拆分为.并将数字部分解析为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。由于我true比使用false OrderByDescending更高,因为我希望不可解析的字符串位于底部。

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