9

我一直在使用以下排序:

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 始终是一串单词,后跟一个连字符,然后是一个数字。

有没有办法让它正确排序?

4

5 回答 5

20

试试这个

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);
    }

}
于 2012-06-15T14:03:56.493 回答
10

这是因为您将它们排序为字符串,并且对于字符串 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()));
于 2012-06-15T14:03:12.273 回答
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);
    }
}
于 2012-06-15T14:17:54.887 回答
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()。

于 2012-07-23T18:21:07.203 回答
0

您可以创建自己的比较器并将其传递给 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());
于 2012-06-15T14:06:14.483 回答