Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I refactor a ReadLine loop to Linq

Tags:

c#

linq

I'd like to make below code cleaner (in the eye of the beholder).

var lines = new StringReader(lotsOfIncomingLinesWithNewLineCharacters);
var resultingLines = new List<string>();

string line;
while( (line = lines.ReadLine() ) != null )
{
    if( line.Substring(0,5) == "value" )
    {
        resultingLines.Add(line);
    }
}

to something like

var resultingLinesQuery = 
    lotsOfIncomingLinesWithNewLineCharacters
    .Where(s=>s.Substring(0,5) == "value );

Hopefully I have illustrated that I'd prefer to not have the result as a list (to not fill up memory) and that StringReader is not mandatory.

There is the naïve solution to create an extension and move the ReadLine there but I have a feeling there might be a better way.

like image 841
LosManos Avatar asked Dec 20 '22 07:12

LosManos


1 Answers

Basically you need a way of extracting lines from a TextReader. Here's a simple solution which will only iterate once:

public static IEnumerable<string> ReadLines(this TextReader reader)
{
    string line;
    while ((line = reader.ReadLine()) != null)
    {
        yield return line;
    }
}

You could use that with:

var resultingLinesQuery = 
    new StringReader(lotsOfIncomingLinesWithNewLineCharacters)
    .ReadLines()
    .Where(s => s.Substring(0,5) == "value");

But ideally, you should be able to iterate over an IEnumerable<T> more than once. If you only need this for strings, you could use:

public static IEnumerable<string> SplitIntoLines(this string text)
{
    using (var reader = new StringReader(text))
    {
        string line;
        while ((line = reader.ReadLine()) != null)
        {
            yield return line;
        }
    }
}

Then:

var resultingLinesQuery = 
    lotsOfIncomingLinesWithNewLineCharacters
    .SplitIntoLines()
    .Where(s => s.Substring(0,5) == "value");
like image 51
Jon Skeet Avatar answered Dec 29 '22 00:12

Jon Skeet