..." />
Well one thing that would make your sample more "LINQy" is an IEnumerable { readonly Func dataSource; public LineReader(string filename) : this(() => File. OpenText(filename)) { } public LineReader(Func dataSource) { this. DataSource = dataSource; } public IEnumerator GetEnumerator() { using (TextReader reader = dataSource()) { string line; while ((line = reader.ReadLine())!
= null) { yield return line; } } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } Now you can use that: var query = from line in new LineReader(filename) let items = line. Split('\t') let myInteger int. Parse(items1); where myInteger == 24809 select line; using (TextWriter writer = File.
CreateText(Application. StartupPath + "\\temp\\test. Txt")) { foreach (string line in query) { writer.
WriteLine(line); } } Note that it would probably be more efficient to not have the let clauses: var query = from line in new LineReader(filename) where int. Parse(line. Split('\t')1) == 24809 select line at which point you could reasonably do it all in "dot notation": var query = new LineReader(filename) .
Where(line => int. Parse(line. Split('\t')1) == 24809) However, I far prefer the readability of the original query :).
Well one thing that would make your sample more "LINQy" is an IEnumerable for reading lines from a file. Here's a somewhat simplified version of my LineReader class from MiscUtil: using System; using System. Collections; using System.Collections.
Generic; using System. IO; public sealed class LineReader : IEnumerable { readonly Func dataSource; public LineReader(string filename) : this(() => File. OpenText(filename)) { } public LineReader(Func dataSource) { this.
DataSource = dataSource; } public IEnumerator GetEnumerator() { using (TextReader reader = dataSource()) { string line; while ((line = reader.ReadLine())! = null) { yield return line; } } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } Now you can use that: var query = from line in new LineReader(filename) let items = line. Split('\t') let myInteger int.
Parse(items1); where myInteger == 24809 select line; using (TextWriter writer = File. CreateText(Application. StartupPath + "\\temp\\test.
Txt")) { foreach (string line in query) { writer. WriteLine(line); } } Note that it would probably be more efficient to not have the let clauses: var query = from line in new LineReader(filename) where int. Parse(line.
Split('\t')1) == 24809 select line; at which point you could reasonably do it all in "dot notation": var query = new LineReader(filename) . Where(line => int. Parse(line.
Split('\t')1) == 24809); However, I far prefer the readability of the original query :).
1 @Jon,I've got your book,It's really great to have such a piece of art. I have one more question - Could you tell me the page where you explain in deep details the LINQ in your book? – John May 21 '09 at 15:41 Your too damn fast Jon.
:) – Matthew Whited May 21 '09 at 15:42 On a similar note, here's blog post on making Streams enumerable: atalasoft. Com/cs/blogs/stevehawley/archive/2009/01/30/… – plinth May 21 '09 at 15:43 1 @John: Glad you like the book :) Chapters 11 and 12 explain LINQ, but chapter 6 covers iterators so that's what you want to understand the LineReader class. (I'm going to use it as an example for the second edition.) If there are any specific details of LINQ which you reckon are missing, please let me know so I can include them in the second edition :) – Jon Skeet May 21 '09 at 15:44 1 @plinth: That's interesting, but I'd prefer the enumerable to take an () => Stream.
That way the iterator can close the stream itself, and potentially open multiple streams (if GetEnumerator is called multiple times). I'm also disturbed at the use of Stream (binary data) to enumerate characters (text data). It should be IEnumerable or use a TextReader instead of a stream.
– Jon Skeet May 21 '09 at 15:46.
101 LINQ Samples is certainly a good collection of examples. Also LINQPad might be a good way to play around with LINQ.
For a website as a starting point, you can try Hooked on LINQ.
If you're after a book, I found LINQ in action from Manning Publications a good place to start.
I got a lot out of the following sites when I started: msdn.microsoft.com/en-us/library/bb42582... weblogs.asp.net/scottgu/archive/2007/05/....
First, I would introduce this method: private IEnumerable ReadLines(StreamReader reader) { while(!reader. EndOfStream) { yield return reader.ReadLine(); } } Then, I would refactor the main method to use it. I put both using statements above the same block, and also added a range check to ensure items1 doesn't fail: private void Filter(string fileName) { using(var writer = File.
CreateText(Application. StartupPath + "\\temp\\test. Txt")) using(var reader = File.
OpenText(filename)) { var myIntegers = from line in ReadLines(reader) let items = line. Split('\t') where items. Length > 1 let myInteger = Int32.
Parse(items1) where myInteger == 24809 select myInteger; foreach(var myInteger in myIntegers) { writer. WriteLine(myInteger); } } }.
It's in a using statement. – Jon Skeet May 21 '09 at 15:57 (Note that it won't dispose it if a caller manually calls MoveNext() and then abandons the iterator, but foreach calls Dispose automatically.) – Jon Skeet May 21 '09 at 15:58 You're right, I mis-read. You aren't using the constructor which takes a Func.
I meant that when you use that function, the LineReader class doesn't fully encapsulate the lifetime of the TextReader instance. – Bryan Watts May 21 '09 at 16:00 As in your example - there are two "where" statements. If the first where statement is not true does it continue to read the linq statement or it leaves it and myIntegers = null?
– John May 21 '09 at 16:02 @Bryan: No, even if you use the constructor which takes a Func my class is responsible for the lifetime of the TextReader itself - the function is only called within the GetEnumerator call. And I am using that constructor, chained from the string constructor. It's the fact that I only keep a Func instead of an actual TextReader which makes it safe.
– Jon Skeet May 21 '09 at 16:09.
I found this article to be extremely crucial to understand LINQ which is based upon so many new constructs brought in in . NET 3.0 & 3.5: I'll warn you it's a long read, but if you really want to understand what Linq is and does I believe it is essential blogs.msdn.com/ericwhite/pages/FP-Tutori... Happy reading.
As for Linq books, I would recommend: Both are excellent books that drill into Linq in detail. To add yet another variation to the as-much-linq-as-possible topic, here's my take: using System; using System.Collections. Generic; using System.IO; using System.
Linq; namespace LinqDemo { class Program { static void Main() { var baseDir = AppDomain.CurrentDomain. BaseDirectory; File. WriteAllLines( Path.
Combine(baseDir, "out. Txt"), File. ReadAllLines(Path.
Combine(baseDir, "in. Txt")) . Select(line => new KeyValuePair(line, line.
Split(','))) // split each line into columns, also carry the original line forward . Where(info => info.Value. Length > 1) // filter out lines that don't have 2nd column .
Select(info => new KeyValuePair(info. Key, int. Parse(info.
Value1))) // convert 2nd column to int, still carrying the original line forward . Where(info => info. Value == 24809) // apply the filtering criteria .
Select(info => info. Key) // restore original lines .ToArray()); } } } Note that I changed your tab-delimited-columns to comma-delimited columns (easier to author in my editor that converts tabs to spaces ;-) ). When this program is run against an input file: A1,2 B,24809,C C E G,24809 The output will be: B,24809,C G,24809 You could improve memory requirements of this solution by replacing "File.
ReadAllLines" and "File. WriteAllLines" with Jon Skeet's LineReader (and LineWriter in a similar vein, taking IEnumerable and writing each returned item to the output file as a new line). This would transform the solution above from "get all lines into memory as an array, filter them down, create another array in memory for result and write this result to output file" to "read lines from input file one by one, and if that line meets our criteria, write it to output file immediately" (pipeline approach).
To answer the first question, there frankly isn't too much reason to use LINQ the way you suggest in the above function except as an exercise. In fact, it probably just makes the function harder to read. LINQ is more useful at operating on a collection than a single element, and I would use it in that way instead.So, here's my attempt at using as much LINQ as possible in the function (make no mention of efficiency and I don't suggest reading the whole file into memory like this): private void Filter(string filename) { using (TextWriter writer = File.
CreateText(Application. StartupPath + "\\temp\\test. Txt")) { using(TextReader reader = File.
OpenText(filename)) { List lines; string line; while((line = reader.ReadLine())! = null) lines. Add(line); var query = from l in lines let splitLine = l.
Split('\t') where int. Parse(splitLine. Skip(1).First()) == 24809 select l; foreach(var l in query) writer.
WriteLine(l); } } }.
If I was to rewrite your filter function using LINQ where possible, it'd look like this: private void Filter(string filename) { using (TextWriter writer = File. CreateText(Application. StartupPath + "\\temp\\test.
Txt")) { var lines = File. ReadAllLines(filename); var matches = from line in lines let items = line. Split('\t') let myInteger = int.
Parse(items1); where myInteger == 24809 select line; foreach (var match in matches) { writer. WriteLine(line) } } }.
Hmm...looks familiar :) (although not sure why you're selecting the int when you want to print the line) – lc. May 21 '09 at 15:37 Note that reading all the lines in one go is a bit of a limiting factor - and unnecessarily so. (See my answer :) – Jon Skeet May 21 '09 at 15:41 It's an issue for big files, obviously.
Jon Skeet's answer is better...sigh, what else is new. :-) – Judah mango May 21 '09 at 16:08 @lc, separation of query and output is nice. I declaratively grabbed the the data via a LINQ query, then did output afterwards.
I like this clean separation. – Judah mango May 21 '09 at 16:12 Will this function compile? Foreach loop is trying to access "line", but line is only available in the Linq statement... – Milan Gardian May 21 '09 at 16:15.
Cannot just check if Linqi is true...Linqi is an IEnumerable (in this case) so have to check like Linqi.First() == true here is a small example: string items = { "12121", "2222", "24809", "23445", "24809" }; var Linqi = from item in items where Convert. ToInt32(item) == 24809 select true; if (Linqi.First() == true) Console. WriteLine("Got a true"); You could also iterate over Linqi, and in my example there are 2 items in the collection.
An example of using as much linq as possible in my function will be very well appreciated. :) – John May 21 '09 at 15:32 love when there is no explanation for a down vote...that should be a requirement. – CSharpAtl May 21 '09 at 16:21 since the question was about SQL and LINQ I did not try to completely rewrite his code.
– CSharpAtl May 21 '09 at 16:27.
If (Linqi == true) writer. How would the function look like using as much Linq as possible? A website/book/article about Linq,but please note I'm a decent beginner in sql/linq.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.