tags:

views:

132

answers:

4

Hello,

I'm new to LINQ,My knowledge on that library is from Jon Skeet's book "C# In Depth 1"

I read a lot of tutorials about LINQ in the past days including Skeet's book,but I could never find out a code snippet showing a normal C# code and then the shorter version of that code with LINQ so the reader can understand what does what.

My Problem: The function below opens a text file and searches for numbers placed at a specific place inside the text file.The numbers(I used ID in the code) start from 1 to 25000 and there are a few that are missing(for example there's no life 25,but 24,23,26,27 etc). I want the code to copy the lines in the array "Ids".Its not meant to be an array,I'm just new and I don't know if anything else would be more handy for LINQ.

    public static IEnumerable<string> ReadLines(StreamReader reader)
    {
        while (!reader.EndOfStream)
        {
            yield return reader.ReadLine();
        }
    }

    static void Filter(string filename)
    {
        using(var writer = File.CreateText(Application.StartupPath + "\\temp\\test.txt"))
        {
            using (var reader = File.OpenText(filename))
            {
                int[] Ids = { 14652, 14653, 14654, 14655, 14656, 14657, 14658, 14659, 14660 };
                var myId = from id in Ids
                           from line in ReadLines(reader)
                           let items = line.Split('\t')
                           where items.Length > 1
                           let ItemId = int.Parse(items[1])
                           where ItemId == id
                           select line;
                foreach (var id in myId)
                {
                    writer.WriteLine(id);
                }

            }
        }
    }

What it writes: It only writes one line with number ,which is the first member of the Ids[] array(14652).

I had to add the second 'from' ,which is placed at first place in the code so it will check it for every member of the array.I get the from statement as a "while",because I couldn't find a snipper with normal code-> linq.

Where is the problem in the code?

+3  A: 
from line in ReadLines(reader)
where Ids.Contains(line.Split('\t')[1])
select line;

You can tweak the Contains with ? to get around splits that don't have an item at 1.

Is this what you're trying to do? I think the second from is like a cross join which Isn't necessary as I understand your problem.

JohnOpincar
Thanks! length=15;
John
+1  A: 

This code is untested, but are you looking for something like this?

var lines = from line in ReadLines(reader)
            let items = line.Split('\t')
            where items.Length > 1
            select new { Text = line, ItemId = int.Parse(items[1]) };

var myId = from id in Ids
           join line in lines on id equals line.ItemId
           select line.Text;
John Fisher
+2  A: 

It only writes one line with number ,which is the first member of the Ids[] array(14652). Where is the problem in the code?

from id in Ids
from line in ReadLines(reader)

This code is conceptually like (ignoring deferred execution):

foreach(int id in Ids)
{
  foreach(string line in ReadLines(reader)
  {
    ...
  }
}

Which will work great for the first id, but then the reader will be at the end of the file for the second id on and no matches will be found.

David B
A: 

You need to perform a join, as if you were joining two tables. Thinking about the process from the standpoint of a SQL query...you have two tables...Ids and Lines. Lines has two fields, Id and Line, and needs to be inner joined to the Ids table. You can accomplish this with the following LINQ query:

var lines = from id in Ids
            join line in
            (
                 from l in ReadLines(reader)
                 let items = l.Split('\t')
                 where items.Length > 1
                 select new { Id = int.Parse(items[1]), Line = l }
            ) on id equals line.Id
            select line.Line;
jrista