2012-01-18 18 views
7

Tengo un List<string>, y algunas de estas cadenas son números. Quiero extraer este subconjunto en un List<int>.Uso de LINQ para extraer entradas de una lista de cadenas

He hecho esto de una manera bastante detallada, como a continuación, pero me da la sensación de que debe haber una manera LINQ más ordenada de estructurar esto. ¿Algunas ideas?

List<string> myStrs = someListFromSomewhere; 
List<int> myInts = new List<int>(); 

foreach (string myStr in myStrs) 
{ 
    int outInt; 
    if (int.TryParse(myStr, out outInt)) 
    { 
     myInts.Add(outInt); 
    } 
} 

Obviamente no necesito una solución a esto - es principalmente para mi educación LINQ.

+2

Otra ocasión que yo declare 'Deseo TryParse volvería un int?' (Lo sé, legado ...) –

+0

ciertamente no más eficiente, pero podrías hacer 'var myInts = myStrs.Where (s => int.TryParse (s, out out)). Seleccionar (s => int.Parse (s)) ', siempre y cuando ya tengas outInt defined. Sin embargo, esto llama 'TryParse' * y * Parse en cada cadena, así que realmente no lo sugeriría – rejj

+2

Esta pregunta podría ser de interés: [consulta LINQ para realizar una proyección, omitiendo casos en los que la proyección causaría una excepción] (http://stackoverflow.com/questions/7188623/linq-query-to-perform-a-projection-skipping-cases-where-the-projection-would-ca) Utilizo su caso exacto como ejemplo. –

Respuesta

23

Puede hacerlo de esta manera:

int parsed = 0; 

myInts = myStrs.Where(x => int.TryParse(x, out parsed)).Select(x => parsed); 

Esto funciona porque la ejecución de los operadores LINQ es diferido, lo que significa:
Para cada elemento de myStrs primero el código en Where se ejecuta y el resultado por escrito en parsed. Y si TryParse devolvió true se ejecuta el código en Select. Este código completo para un elemento se ejecuta antes de que todo este código se ejecute para el próximo artículo.

+3

me parece muy frágil. – dtb

+1

@dtb: No, en absoluto. Si lo hace, realmente no entiende el funcionamiento interno de LINQ. –

+1

Solo digo que requiere demasiado conocimiento del funcionamiento interno de LINQ para mi gusto. – dtb

7

Los parámetros LINQ y out no se combinan bien. Usted puede hacer esto:

var myInts = myStrs 
    .Select(s => 
    { 
     int outInt; 
     return int.TryParse(s, out outInt) ? (int?)outInt : null; 
    }) 
    .Where(i => i.HasValue) 
    .Select(i => i.Value) 
    .ToList(); 
+0

+1 - Exactamente la solución que estaba a punto de publicar. –

+4

Overkill absoluto –

+0

¿Esto * realmente * merece un voto a favor? No está mal ¿verdad? – Yuck

0

Dado que se trata de la educación de LINQ ... Si realmente está buscando la manera esto se puede hacer con la sintaxis de LINQ solamente, Otra opción es mover la lógica de análisis a una clase que encapsula el resultado y el valor.

var myInts = from val in myStrs 
      let parserVal = new Parser(val) 
      where parserVal.IsInt 
      select parserVal.Val; 

donde Parser es algo como esto ...

class Parser 
{ 
     public bool IsInt { get; set; } 
     public int Val { get; set; } 

     public Parser(string val) 
     { 
      int outVal; 
      IsInt = int.TryParse(val, out outVal); 
      if (IsInt) 
      { 
       Val = outVal; 
      } 
     } 
} 
Cuestiones relacionadas