LINQ для начинающих
Мне нравится С#, мне нравится фреймворк, и я также люблю учиться как можно больше. Сегодня я начал читать статьи о LINQ в С#, и я не мог найти ничего хорошего для новичка, который никогда не работал с SQL в своей жизни.
Я нашел эту статью очень полезной, и я понял ее небольшие части, но я хотел бы получить больше примеров.
Прочитав пару раз, я попытался использовать LINQ в своей функции, но я не смог.
private void Filter(string filename)
{
using (TextWriter writer = File.CreateText(Application.StartupPath + "\\temp\\test.txt"))
{
using(TextReader reader = File.OpenText(filename))
{
string line;
while((line = reader.ReadLine()) != null)
{
string[] items = line.Split('\t');
int myInteger = int.Parse(items[1]);
if (myInteger == 24809) writer.WriteLine(line);
}
}
}
}
Это то, что я сделал, и это не сработало, результат всегда был ложным.
private void Filter(string filename)
{
using (TextWriter writer = File.CreateText(Application.StartupPath + "\\temp\\test.txt"))
{
using(TextReader reader = File.OpenText(filename))
{
string line;
while((line = reader.ReadLine()) != null)
{
string[] items = line.Split('\t');
var Linqi = from item in items
where int.Parse(items[1]) == 24809
select true;
if (Linqi == true) writer.WriteLine(line);
}
}
}
}
Я прошу две вещи:
- Как бы выглядела функция с использованием максимально возможного Linq?
- Веб-сайт/книга/статья о Linq, но, пожалуйста, обратите внимание, что я достойный новичок в sql/linq.
Заранее благодарю вас!
Ответы
Ответ 1
Ну, одна вещь, которая сделает ваш образец более "LINQy" IEnumerable<string>
для чтения строк из файла. Здесь несколько упрощенная версия моего класса LineReader
из MiscUtil:
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
public sealed class LineReader : IEnumerable<string>
{
readonly Func<TextReader> dataSource;
public LineReader(string filename)
: this(() => File.OpenText(filename))
{
}
public LineReader(Func<TextReader> dataSource)
{
this.dataSource = dataSource;
}
public IEnumerator<string> GetEnumerator()
{
using (TextReader reader = dataSource())
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Теперь вы можете использовать это:
var query = from line in new LineReader(filename)
let items = line.Split('\t')
let myInteger int.Parse(items[1]);
where myInteger == 24809
select line;
using (TextWriter writer = File.CreateText(Application.StartupPath
+ "\\temp\\test.txt"))
{
foreach (string line in query)
{
writer.WriteLine(line);
}
}
Обратите внимание, что, вероятно, более эффективно не иметь предложения let
:
var query = from line in new LineReader(filename)
where int.Parse(line.Split('\t')[1]) == 24809
select line;
в этот момент вы можете разумно сделать все это в "точечной нотации":
var query = new LineReader(filename)
.Where(line => int.Parse(line.Split('\t')[1]) == 24809);
Однако я предпочитаю читаемость исходного запроса:)
Ответ 2
101 Образцы LINQ, безусловно, хорошая коллекция примеров. Также LINQPad может быть хорошим способом играть с LINQ.
Ответ 3
Для веб-сайта в качестве отправной точки вы можете попробовать Подключено к LINQ
Изменить:
Исходный сайт сейчас мертв (домен продается).
Здесь находится интернет-архив последней версии: https://web.archive.org/web/20140823041217/http://www.hookedonlinq.com/
Ответ 4
Если вы после книги, я нашел LINQ в действии из Manning Publications - хорошее место для начала.
Ответ 5
Примеры MSDN LINQ: http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx
Ответ 6
Я получил много из следующих сайтов, когда начал:
http://msdn.microsoft.com/en-us/library/bb425822.aspx
http://weblogs.asp.net/scottgu/archive/2007/05/19/using-linq-to-sql-part-1.aspx
Ответ 7
Сначала я бы представил этот метод:
private IEnumerable<string> ReadLines(StreamReader reader)
{
while(!reader.EndOfStream)
{
yield return reader.ReadLine();
}
}
Затем я бы реорганизовал основной метод его использования. Я поставил оба оператора using
над одним и тем же блоком, а также добавил проверку диапазона, чтобы гарантировать, что items[1]
не работает:
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(items[1])
where myInteger == 24809
select myInteger;
foreach(var myInteger in myIntegers)
{
writer.WriteLine(myInteger);
}
}
}
Ответ 8
Что касается книг Linq, я бы порекомендовал:
(источник: ebookpdf.net)
http://www.diesel-ebooks.com/mas_assets/full/0321564189.jpg
Обе прекрасные книги, в которых подробно рассказывается о Linq.
Чтобы добавить еще одну вариацию к теме "как можно больше linq-как-возможно", вот мой взгляд:
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<string, string[]>(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<string, int>(info.Key, int.Parse(info.Value[1]))) // 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());
}
}
}
Обратите внимание, что я изменил ваши столбцы с разделителями-табуляцией на столбцы с разделителями-запятыми (проще написать в моем редакторе, который преобразует вкладки в пробелы ;-)). Когда эта программа запускается для входного файла:
A1,2
B,24809,C
C
E
G,24809
Выход будет:
B,24809,C
G,24809
Вы можете улучшить требования к памяти для этого решения, заменив "File.ReadAllLines" и "File.WriteAllLines" на Jon Skeet LineReader (и LineWriter в том же духе, взяв IEnumerable и записав каждый возвращенный элемент в выходной файл в качестве новой строки). Это преобразовало бы приведенное выше решение из "получить все строки в память как массив, отфильтровать их, создать другой массив в памяти для результата и записать этот результат в выходной файл, чтобы" читать "строки из входного файла одну за другой, и если это строка соответствует нашим критериям, немедленно запишите ее в выходной файл "(конвейерный подход).
Ответ 9
Я нашел эту статью чрезвычайно важной для понимания LINQ, которая основана на множестве новых конструкций, внедренных в .NET 3.0 и 3.5:
Я предупреждаю вас, что это долго читается, но если вы действительно хотите понять, что такое Linq, и я считаю, что это важно
http://blogs.msdn.com/ericwhite/pages/FP-Tutorial.aspx
Счастливое чтение
Ответ 10
Если бы я мог переписать функцию фильтра, используя LINQ, где это было возможно, это выглядело бы так:
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(items[1]);
where myInteger == 24809
select line;
foreach (var match in matches)
{
writer.WriteLine(line)
}
}
}
Ответ 11
Чтобы ответить на первый вопрос, откровенно не слишком много причин использовать LINQ так, как вы предлагаете в вышеперечисленной функции, кроме как упражнение. Фактически, это, вероятно, просто затрудняет чтение функции.
LINQ более полезен при работе над коллекцией, чем один элемент, и я бы использовал его таким образом. Итак, здесь моя попытка использовать как можно больше LINQ в функции (не упоминайте об эффективности, и я не предлагаю прочитать весь файл в памяти, как это):
private void Filter(string filename)
{
using (TextWriter writer = File.CreateText(Application.StartupPath + "\\temp\\test.txt"))
{
using(TextReader reader = File.OpenText(filename))
{
List<string> 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);
}
}
}
Ответ 12
не может просто проверить, истинна ли Linqi... Linqi - это IEnumerable<bool>
(в данном случае), поэтому нужно проверить, как Linqi.First() == true
вот небольшой пример:
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");
Вы также можете перебирать Linqi, и в моем примере в коллекции есть 2 элемента.