2011-02-25 57 views
8

Tengo una lista de cadenas, y estas cadenas contienen números y palabras.Linq - Ordenar por número luego letras

Lo que quería hacer es pedir que por los números (por orden numérico), seguido de las palabras (por orden alfabético)

Mi lista no contiene una mezcla de los dos ... aquí es un ejemplo

1, 5, 500, LT, RT, 400 -> LINQ -> 1, 5, 400, 500, LT, RT

Aquí está un ejemplo de lo que tengo, que funciona, pero Me preguntaba si hay una mejor manera de escribirlo.

  int results = 0; 
      // Grabs all voltages 
      var voltage = ActiveRecordLinq.AsQueryable<Equipment>() 
       .OrderBy(x => x.Voltage) 
       .Select(x => x.Voltage) 
       .Distinct() 
       .ToList(); 
      // Order by numeric 
      var numberVoltage = voltage 
       .Where(x => int.TryParse(x, out results)) 
       .OrderBy(x => Convert.ToInt32(x)); 
      // Then by alpha 
      var letterVoltage = voltage 
       .Where(x=> !String.IsNullOrEmpty(x)) 
       .Where(x => !int.TryParse(x, out results)) 
       .OrderBy(x => x); 

      return numberVoltage.Union(letterVoltage) 

¡Gracias por la ayuda!

+0

¿Por qué mantiene el análisis int, ¿el voltaje no está definido como int? – Jimmy

+0

@Jimmy - No, el voltaje no se define como int porque contiene algunas palabras, en este caso "LT". También se define como cadena en la base de datos – ChickSentMeHighE

Respuesta

17

Dado que usted está haciendo todo en proceso (y cuando usted tiene una llamada ToList) Creo que sólo haría uso de un comparador personalizado:

return ActiveRecordLinq.AsQueryable<Equipment>() 
         .Select(x => x.Voltage) 
         .Distinct() 
         .AsEnumerable() // Do the rest in-process 
         .Where(x => !string.IsNullOrEmpty(x)) 
         .OrderBy(x => x, new AlphaNumericComparer()) 
         .ToList(); 

Dónde AlphaNumericComparer implementa IComparer<string>, algo así como esto:

public int Compare(string first, string second) 
{ 
    // For simplicity, let's assume neither is null :) 

    int firstNumber, secondNumber; 
    bool firstIsNumber = int.TryParse(first, out firstNumber); 
    bool secondIsNumber = int.TryParse(second, out secondNumber); 

    if (firstIsNumber) 
    { 
     // If they're both numbers, compare them; otherwise first comes first 
     return secondIsNumber ? firstNumber.CompareTo(secondNumber) : -1; 
    } 
    // If second is a number, that should come first; otherwise compare 
    // as strings 
    return secondIsNumber ? 1 : first.CompareTo(second); 
} 

Usted podría utilizar un condicional gigante para la última parte:

public int Compare(string first, string second) 
{ 
    // For simplicity, let's assume neither is null :) 

    int firstNumber, secondNumber; 
    bool firstIsNumber = int.TryParse(first, out firstNumber); 
    bool secondIsNumber = int.TryParse(second, out secondNumber); 

    return firstIsNumber 
     ? secondIsNumber ? firstNumber.CompareTo(secondNumber) : -1; 
     : secondIsNumber ? 1 : first.CompareTo(second); 
} 

... pero en este caso no creo que lo haga :)

+0

¡Funciona muy bien! ¡Gracias! – ChickSentMeHighE

6

Esta solución intenta analizar una vez para cada valor.

List<string> voltage = new List<string>() { "1", "5", "500" , "LT", "RT", "400" }; 

List<string> result = voltage 
    .OrderBy(s => 
    { 
    int i = 0; 
    return int.TryParse(s, out i) ? i : int.MaxValue; 
    }) 
    .ThenBy(s => s) 
    .ToList(); 
Cuestiones relacionadas