Come posso ordinare una stringa di testo seguita da un numero usando LINQ

Ho usato il seguente tipo:

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

Tuttavia ho un problema perché il mio ShortTitle ha questo aspetto:

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

Quando ordino questo usando LINQ, viene nell’ordine

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

Il ShortTitle è sempre una stringa di parole seguita da un trattino singolo e quindi da un numero.

C’è un modo per ottenere questo per ordinare correttamente?

È perché li stai ordinando come stringhe, e per le stringhe 11 arriva prima 2. Avrai bisogno di analizzare il ShortTitle per darti il ​​valore int (sto assumendo) alla fine, e ordinare per quello.

La tua query LINQ può essere modificata in questo modo affinché funzioni:

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

Prova questo

 List list = new List() { "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 CustomSort(this IEnumerable 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); } } 

veloce e sporco:

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

In ritardo alla festa, ma non lascerò che questo mi fermi!

Piggybacking sulla bella soluzione di @ 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); 

In realtà, la differenza principale è catturare il risultato della divisione in modo da non dover fare nuovamente lo split per ottenere l’indice e quindi ho aggiunto un Trim () al titolo.

Puoi creare il tuo Comparer e passarlo a OrderBy o ThenBy per ordinare la stringa nel modo desiderato.

Ad esempio, questo comparatore molto primitivo, riempirà l’ultimo numero con 0 prima di convertire le stringhe:

 class MyComparer:Comparer { 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); } } 

e puoi chiamarlo con modifiche minime:

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