C # Linq / Lambda expression: how to select an integer from a string?

I think the best way to explain my question is with a short (general) linq-to-objects code example:

IEnumerable<string> ReadLines(string filename) { string line; using (var rdr = new StreamReader(filename)) while ( (line = rdr.ReadLine()) != null) yield return line; } IEnumerable<int> XValuesFromFile(string filename) { return ReadLines(filename) .Select(l => l.Substring(3,3)) .Where(l => int.TryParse(l)) .Select(i => int.Parse(i)); } 

Note that this code parses an integer twice. I know that I don’t have an obvious easy way to avoid one of these calls safely (namely because I did it before). I just can't find it right now. How can i do this?

+4
source share
3 answers

I think I'll go with something like this:

 IEnumerable<O> Reduce<I,O>(this IEnumerable<I> source, Func<I,Tuple<bool, O>> transform ) { foreach (var item in source) { try { Result<O> r = transform(item); if (r.success) yield return r.value; } catch {} } } ReadLines().Reduce(l => { var i; new Tuple<bool, int>(int.TryParse(l.Substring(3,3),i), i)} ); 

I don’t really like it, although I’m already on the record, because I don’t like to use tuples in this way . Unfortunately, I don't see many alternatives beyond abuse of exceptions or restricting it to reference types (where null is defined as a failed conversion), none of which are much better.

+3
source

What about:

 int? TryParse(string s) { int i; return int.TryParse(s, out i) ? (int?)i : (int?)null; } IEnumerable<int> XValuesFromFile(string filename) { return from line in ReadLines(filename) let start = line.Substring(3,3) let parsed = TryParse(start) where parsed != null select parsed.GetValueOrDefault(); } 

Perhaps you could combine the second / third lines if you want:

  return from line in ReadLines(filename) let parsed = TryParse(line.Substring(3,3)) 

The choice of GetValueOrDefault is that it skips the validation check performed by the (int) or .Value command, that is, it (ever a little) is faster (and we already checked that it is not null ).

+9
source

This is not entirely beautiful, but you can do:

 return ReadLines(filename) .Select(l => { string tmp = l.Substring(3, 3); int result; bool success = int.TryParse(tmp, out result); return new { Success = success, Value = result }; }) .Where(i => i.Success) .Select(i => i.Value); 

Of course, this basically just pushes the work into a lambda, but it gives the correct answers with one analysis (but with additional memory allocations).

+3
source

Source: https://habr.com/ru/post/1300098/


All Articles