2012-01-18 5 views
7

Ho uno List<string> e alcune di queste stringhe sono numeri. Voglio estrarre questo sottoinsieme in un List<int>.Utilizzo di LINQ per estrarre int da un elenco di stringhe

Ho fatto questo in modo abbastanza prolisso - come di seguito - ma ho la sensazione che ci debba essere un LINQ più ordinato per strutturarlo. Qualche idea?

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

Ovviamente non ho bisogno una soluzione a questo - è soprattutto per la mia formazione LINQ.

+2

Un'altra occasione per me di dichiarare 'Vorrei TryParse sarebbe tornato un int?' (Lo so, legacy ...) –

+0

certamente non più efficiente, ma si potrebbe fare 'var myInts = myStrs.Where (s => int.TryParse (s, out outInt)). Select (s => int.Parse (s)) ', a patto che tu abbia già definito OutInt. Ciò chiama 'TryParse' * e * Parse su ogni stringa, anche se - quindi non lo suggerirei veramente – rejj

+2

Questa domanda potrebbe essere di interesse: [Query LINQ per eseguire una proiezione, saltando i casi in cui la proiezione causerebbe un'eccezione] (http://stackoverflow.com/questions/7188623/linq-query-to-perform-a-projection-skipping-cases-where-the-projection-would-ca) Uso il tuo caso esatto come esempio. –

risposta

23

Si può fare in questo modo:

int parsed = 0; 

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

Questo funziona perché l'esecuzione di operatori LINQ è differito, il che significa:
Per ogni elemento myStrs prima il codice Where viene eseguita e il risultato scritto in parsed. E se TryParse ha restituito true il codice in Select viene eseguito. L'intero codice per un articolo viene eseguito prima che l'intero codice venga eseguito per l'elemento successivo.

+3

Sembra molto fragile per me. – dtb

+1

@dtb: Niente affatto. Se lo fa, non capisci veramente il funzionamento interno di LINQ. –

+1

Solo dicendo che richiede troppa conoscenza del funzionamento interno di LINQ per i miei gusti. – dtb

7

I parametri LINQ e out non si combinano bene. Si potrebbe fare questo:

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 - Esattamente la soluzione che stavo per postare. –

+4

Overkill assoluto –

+0

Questo * davvero * merita un downvote? Non è sbagliato vero? – Yuck

0

Dal momento che questo è per l'educazione LINQ ... Se davvero siete alla ricerca di come questo può essere fatto solo con la sintassi LINQ, Un'altra opzione è quella di spostare la logica di analisi a una classe che incapsula il risultato e il valore.

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

dove Parser è qualcosa di simile ...

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; 
      } 
     } 
} 
Problemi correlati