使用特殊字符对一组值进行排序

时间:2016-05-17 08:39:05

标签: c# wpf sorting enumerable

我有一项任务是在DataTable中对一组值进行排序。最棘手的部分是值具有像'。'这样的特殊字符。或' - '和负值。以下图片是我目前的输出: enter image description here

数据以';'分隔在图片里。 我使用以下代码对数据进行排序。

DataTable myDataTable = new DataTable();
        myDataTable.Columns.Add("SN", typeof(string));
        string myValues = "";

        if (!File.Exists("d:\\DUDBC-values.txt")) //DUDBC-values.txt
        {
            Console.WriteLine("No file found");
            Console.ReadKey();
            return;
        }
        StreamReader file = new StreamReader("d:\\DUDBC-values.txt");
        string line;
        while ((line = file.ReadLine()) != null)
        {
            myValues += line;
            myValues += ";";
        }
        file.Close();


        string[] myValuesArray = myValues.Split(';');
        myValuesArray = myValuesArray.Take(myValuesArray.Count() - 1).ToArray();

        foreach (string myValue in myValuesArray)
        {
            DataRow myRow = myDataTable.NewRow();
            myRow["SN"] = myValue;
            myDataTable.Rows.Add(myRow);
        }

        string beforeSort = string.Join(";", myDataTable.AsEnumerable().Select(x => x["SN"]));
        Console.WriteLine("Before Sorting:");
        Console.WriteLine();

        Console.WriteLine(beforeSort);

        Console.WriteLine();


        IEnumerable<DataRow> sortedValues = myDataTable.AsEnumerable()
                                                 .OrderBy(x =>
                                                 {
                                                     string currentStringValue = x["SN"].ToString();
                                                     char[] SplitChar = new char[] { '.', '-' };
                                                     string[] currentStringValueArray = new string[1];
                                                     try
                                                     {
                                                         float val = float.Parse(currentStringValue);
                                                         currentStringValueArray[0] = currentStringValue;

                                                     }
                                                     catch { 
                                                     currentStringValueArray = currentStringValue.Split(SplitChar);
                                                     }

                                                     string currentPart = "";
                                                     int currentPartNumeric = 0;


                                                     if (currentStringValueArray.Length > 1)
                                                     {
                                                         for (int i = 0; i < currentStringValueArray.Length; i++)
                                                         {
                                                             if (int.TryParse(currentStringValueArray[i], out currentPartNumeric))
                                                             {
                                                                 if (i >= 1)
                                                                     currentPart += ".";
                                                                 currentPart += currentPartNumeric.ToString();
                                                             }
                                                             else
                                                             {
                                                                 try
                                                                 {
                                                                     if (i >= 1)
                                                                         currentPart += ".";
                                                                     currentPart += (((int)(char.ToUpper(char.Parse(currentStringValueArray[i])))) - 64).ToString();
                                                                 }
                                                                 catch { }
                                                             }

                                                         }
                                                         return Convert.ToString(currentPart, CultureInfo.InvariantCulture);
                                                     }

                                                     else
                                                         return 0m.ToString();
                                                 });
string afterSort = string.Join(";", sortedValues.Select(x => x["SN"]));
        Console.WriteLine("After Sorting:");
        Console.WriteLine();

        Console.WriteLine(afterSort);
        //Copy to your existing datatable
        myDataTable = sortedValues.CopyToDataTable();
        Console.ReadKey();

我原以为它是这样的:

-1
1.1.a.1
1.2.a.1
1.2.a.2
1.2.a.3
1.3.1
2.1.2
2.1a.1
2.1a.2
2.5
2.6.1
2.7.1
2.7.2
2.7.16
2.25a
2.25b
2.42.1
2.42.2
3.1.1
3.1.2
3.5.2
3.6a.1
3.6a.2
3.6b.2
5.1a.1
5.1a.2
5.1a.3
5.1b.1
5.1b.2
5.1b.6
6.3.1
6.3.2
6.3.3
6.3.4
6.3.5
6.5.1
6.5.2-C11
6.5.3-C12
17.06.01.b.i
17.06.02.b.i
17.06.02.b.vi
18.01.b
18.02.01.b.iii
1000

我做错了什么?需要帮助。在用户不断使用不同类型的值之前,我也曾问过这类问题in this post

1 个答案:

答案 0 :(得分:2)

看起来您需要对所谓的“自然排序顺序”进行排序。

您可以使用Windows API函数StrCmpLogicalW()进行此类比较。

您可以将其包装在一组扩展方法中,以便对List<T>或数组进行排序,如下所示:

public static class NaturalSortExt
{
    /// <summary>Sorts a list in "Natural sort order", i.e. "9" sorts before "10".</summary>
    /// <typeparam name="T">The type of elements in the list to be sorted.</typeparam>
    /// <param name="self">The list to be sorted.</param>
    /// <param name="stringSelector">A projection to convert list elements to strings for comparision.</param>

    public static void SortNatural<T>(this List<T> self, Func<T, string> stringSelector)
    {
        self.Sort((lhs, rhs) => StrCmpLogicalW(stringSelector(lhs), stringSelector(rhs)));
    }

    /// <summary>Sorts a list in "Natural sort order", i.e. "9" sorts before "10".</summary>
    /// <param name="self">The list to be sorted.</param>

    public static void SortNatural(this List<string> self)
    {
        self.Sort(StrCmpLogicalW);
    }

    /// <summary>Sorts an array in "Natural sort order", i.e. "9" sorts before "10".</summary>
    /// <param name="self">The array to be sorted.</param>

    public static void SortNatural(this string[] self)
    {
        Array.Sort(self, StrCmpLogicalW);
    }

    [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
    static extern int StrCmpLogicalW(string lhs, string rhs);
}

然后您可以对数组(或List<T>)进行排序,如下面的示例代码所示:

class Program
{
    static void Main()
    {
        string[] test =
        {
            "3.1.2",
            "1.2.a.1",
            "1.2.a.2",
            "1.3.1",
            "2.1.2",
            "2.1a.2",
            "2.1a.1",
            "-1",
            "2.5",
            "2.7.1",
            "1.1.a.1",
            "2.7.16",
            "2.7.2",
            "2.25a",
            "2.6.1",
            "5.1a.3",
            "2.42.2",
            "2.25b",
            "2.42.1",
            "3.6a.2",
            "5.1b.1",
            "3.1.1",
            "3.5.2",
            "3.6a.1",
            "3.6b.2",
            "5.1a.1",
            "1.2.a.3",
            "5.1b.2",
            "5.1b.6",
            "6.3.1",
            "6.3.2",
            "17.06.02.b.i",
            "6.3.3",
            "5.1a.2",
            "6.3.4",
            "6.3.5",
            "6.5.1",
            "1000",
            "6.5.2-C11",
            "6.5.3-C12",
            "17.06.01.b.i",
            "17.06.02.b.vi",
            "18.01.b",
            "18.02.01.b.iii"
        };

        string[] expected =
        {
            "-1",
            "1.1.a.1",
            "1.2.a.1",
            "1.2.a.2",
            "1.2.a.3",
            "1.3.1",
            "2.1.2",
            "2.1a.1",
            "2.1a.2",
            "2.5",
            "2.6.1",
            "2.7.1",
            "2.7.2",
            "2.7.16",
            "2.25a",
            "2.25b",
            "2.42.1",
            "2.42.2",
            "3.1.1",
            "3.1.2",
            "3.5.2",
            "3.6a.1",
            "3.6a.2",
            "3.6b.2",
            "5.1a.1",
            "5.1a.2",
            "5.1a.3",
            "5.1b.1",
            "5.1b.2",
            "5.1b.6",
            "6.3.1",
            "6.3.2",
            "6.3.3",
            "6.3.4",
            "6.3.5",
            "6.5.1",
            "6.5.2-C11",
            "6.5.3-C12",
            "17.06.01.b.i",
            "17.06.02.b.i",
            "17.06.02.b.vi",
            "18.01.b",
            "18.02.01.b.iii",
            "1000"
        };

        test.SortNatural();

        Debug.Assert(test.SequenceEqual(expected));

        Console.WriteLine(string.Join("\n", test));
    }
}