2014-01-15 4 views
2

Выполняют ли методы Linq в стеке IEnumerable или переопределяют предыдущие методы?Можете ли вы складывать несколько запросов IEnumerable?

Например

string[] exampleArray = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; 
IEnumerable<string> iEnum1 = exampleArray.Skip(1); 
IEnumerable<string> iEnum2 = iEnum1.Take(5); 
IEnumerable<string> iEnum3 = iEnum2.Skip(1); 
IEnumerable<string> iEnum4 = iEnum3.Take(2); 
int count = iEnum4.Count(); 

Могу ли я рассчитывать на count равно 2 и я мог еще ожидать iEnum3 перечислить через , если я хочу, чтобы повторно использовать, что IEnumerable?

Я пытаюсь избежать создания новых массивов, даже если они будут логически проще работать, поскольку начальный массив будет относительно большим (уже из более крупного потока файлов).

+1

Возможно, вы захотите взглянуть на значения в отладчике или распечатать их на консоли. –

+0

Вы можете написать это, как этот exampleArray.Skip (1) .Выберите (5) .Skip (1) .Take (2) .Count(); –

ответ

3

Они делают «стек», как вы выразились (обычно называемый «цепочкой»).

Эти заявления LINQ (Take, Скипа) являются расширениями IEnumerable, и конечный результат будет, что iEnum4 является exampleArray.Skip(1).Take(5).Skip(1).Take(2)

Окончательная оценка этого заявления откладывается до тех пор, некоторые методы не называются (например, Count), в этот момент выполняется инструкция LINQ, и конечный результат сохраняется в переменной int count.

Могу ли я рассчитывать рассчитывать на равное 2, и я мог еще ожидать iEnum3 перечислить через «3», «4», «5», «6», если я хочу, чтобы повторно использовать, что IEnumerable?

Да, iEnum3 будет оценивать то, что LINQ запрос в нем содержится, например, что iEnum3.Count() может оценить другое значение, чем iEnum4.Count(). Но если вы вызываете iEnum3.Count() три разных раза в вашей программе, вы можете получить три разных результата, потому что оценка отложена, и значения в exampleArray могут быть изменены тем временем.

+0

iEnum3.Count изменится только в том случае, если 'exampleArray' был тип набора, который может измениться правильно? Поскольку 'exampleArray' является' Array', и вы не можете изменить размер 'Array' после его инициализации? – Puddler

+0

Да, это правильно, если у вас есть что-то с фиксированным количеством элементов, то счет останется прежним. С другой стороны, если вы делали '.Sum()' вместо '.Count()', то выполнение 'exampleArray [3] =" 3000 ";' для изменения "3" на "3000" конечно, эффект. –

1

Да count будет равен 2. Давайте разбить его:

var iEnum1 = exampleArray.Skip(1); // { "2", "3", "4", "5", "6", "7", "8", "9" } 
var iEnum2 = iEnum1.Take(5);  // { "2", "3", "4", "5", "6" } 
var iEnum3 = iEnum2.Skip(1);  // { "3", "4", "5", "6" } 
var iEnum4 = iEnum3.Take(2);  // { "3", "4" } 
int count = iEnum4.Count();  // 2 

И конечно же, вы можете цепи их вместе, как это:

int count = exampleArray.Skip(1).Take(5).Skip(1).Take(2).Count() 

Важно отметить, однако, что Linq Запросы: lazy. Это означает, что они фактически не оцениваются до тех пор, пока вы не перейдете к набору результатов. В приведенных выше комментариях указывается только то, что переменная будет быть, если вы проверили результат, но Linq не фактически произведите результат, пока это не понадобится (например, когда вы звоните Count). Поэтому, хотя вы можете повторно использовать iEnum3 в других запросах Linq, это, вероятно, не принесет никакой пользы от производительности —, хотя это может способствовать повторному использованию/удобочитаемости кода.

+0

Итак, вам нужно использовать ToArray после принятия 4-й строки, если вы хотите кэшировать iEnum3 без перфоманса каждый раз, когда вы перечисляете его. – csaam

+0

@csaam Вам нужно будет сделать это после 'Skip' на линии 3. Вы также можете использовать' ToList' (что очень немного быстрее). –

+0

Да, я смешал свои переменные в моей голове, что плохо. Я не знал, что ToList был быстрее. У вас есть ссылка на то, что мне интересно. – csaam

Смежные вопросы