如何使用LINQ对一串文本后跟一个数字进行排序

时间:2012-06-15 13:59:27

标签: c# linq

我一直在使用以下类别:

var query = _cityRepository.GetAll(
               .OrderBy(item => item.RowKey.Substring(0, 4))
               .ThenBy(item => item.ShortTitle)

但是我遇到了问题,因为我的ShortTitle看起来像这样:

Liverpool - 1
Liverpool - 2
...
Liverpool - 9
Liverpool - 10
Liverpool - 11
West Kirby - 1
West Kirby - 8
West Kirby - 12

当我使用LINQ对它进行排序时,它按顺序

Liverpool - 1
Liverpool - 11
Liverpool - 12
Liverpool - 2
West Kirby - 1
West Kirby - 12
West Kirby - 8

ShortTitle总是一串单词,后跟一个连字符,然后是一个数字。

有没有办法可以正确排序?

5 个答案:

答案 0 :(得分:16)

试试这个

List<string> list = new List<string>() { 
    "Liverpool - 1",
    "Liverpool - 11",
    "Liverpool - 12",
    "Liverpool - 2",
    "West Kirby - 1",
    "West Kirby - 12",
    "West Kirby - 8" };
var sortedList = list.CustomSort().ToArray();    


public static class MyExtensions
{
    public static IEnumerable<string> CustomSort(this IEnumerable<string> list)
    {
        int maxLen = list.Select(s => s.Length).Max();

        return list.Select(s => new
        {
            OrgStr = s,
            SortStr = Regex.Replace(s, @"(\d+)|(\D+)", m => m.Value.PadLeft(maxLen, char.IsDigit(m.Value[0]) ? ' ' : '\xffff'))
        })
        .OrderBy(x => x.SortStr)
        .Select(x => x.OrgStr);
    }

}

答案 1 :(得分:9)

这是因为你将它们排序为字符串,而字符串11则排在第2位之前。你需要解析ShortTitle来给你(我假设)int的值。结束,并按此排序。

您的LINQ查询可以更改为此以使其正常工作:

var query = _cityRepository.GetAll(
           .OrderBy(item => item.RowKey.Substring(0, 4))
           .ThenBy(item => item.ShortTitle.Split('-').First())
           .ThenBy(item => Convert.ToInt16(item.ShortTitle.Split().Last()));

答案 2 :(得分:3)

快速而肮脏:

class Program
{
    static void Main(string[] args)
    {
        var list = new[] {"Liverpool - 1", 
                          "Liverpool - 11",
                          "Liverpool - 123",
                          "Liverpool - 342",
                          "Liverpool - 2"};

        foreach (var x in list.OrderBy(s => Int32.Parse(Regex.Match(s, @"- (\d*)").Groups[1].Value)))
            Console.WriteLine(x);
    }
}

答案 3 :(得分:1)

晚会,但我不会让那阻止我!

捎带@ NominSim的好解决方案:

var query = _cityRepository.GetAll()
           .Select(item => 
             {
               var fields = item.ShortTitle.Split('-');
               return new
               {
                 Key = item.RowKey.Substring(0,4),
                 Title = fields[0].Trim(),
                 Index = Convert.ToInt16(fields[1])
               }
             })
           .OrderBy(item => item.Key)
           .ThenBy(item => item.Title)
           .ThenBy(item => item.Index);

实际上,主要区别在于捕获拆分的结果,这样我们就不必再次进行拆分来获取索引,然后我在Title中添加了一个Trim()。

答案 4 :(得分:0)

您可以创建自己的Comparer并将其传递给OrderBy或ThenBy,让它们按照您想要的方式排序。

例如,这个非常原始的比较器将在转换字符串之前用0填充最后一个数字:

class MyComparer:Comparer<string>
{
    public override int Compare(string x, string y)
    {
        var xL = xparts[xparts.Length - 1];
        long xN;
        if (long.TryParse(xL,out xN))
        {
            xparts[xparts.Length - 1] = xN.ToString().PadLeft(20,'0');
        }

        var yL = yparts[yparts.Length - 1];
        long yN;
        if (long.TryParse(yL, out yN))
        {
            yparts[yparts.Length - 1] = yN.ToString().PadLeft(20, '0');
        }

        var x2=String.Join(" ", xparts);
        var y2 = String.Join(" ", yparts);

        return x2.CompareTo(y2);
    }
}

你可以用最小的改变来调用它:

var query = _cityRepository.GetAll(
           .OrderBy(item => item.RowKey.Substring(0, 4))
           .ThenBy(item => item.ShortTitle, new MyComparer());