Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are these linq outputs different? [duplicate]

Tags:

c#

linq

1st statement:

IEnumerable<char> query = "Not what you might expect";  query = query.Where (c => c != 'a'); query = query.Where (c => c != 'e'); query = query.Where (c => c != 'i'); query = query.Where (c => c != 'o'); query = query.Where (c => c != 'u'); 

Output of String.Join("", query): "Nt wht y mght xpct"

2nd statement:

query = "Not what you might expect";  foreach (char vowel in "aeiou")     query = query.Where (c => c != vowel); 

Output of String.Join("", query): "Not what yo might expect"

The outputs from these statements are different. Can any one explain why?

like image 919
Rohit Prakash Avatar asked Feb 27 '13 13:02

Rohit Prakash


People also ask

How do I remove duplicate values in LINQ?

How to remove the duplicates in the list using linq? You can also do var set = new HashSet<int>(); var uniques = items. Where(x => set. Add(x.Id)); .

What does => mean in LINQ?

The => operator can be used in two ways in C#: As the lambda operator in a lambda expression, it separates the input variables from the lambda body. In an expression body definition, it separates a member name from the member implementation.

Is LINQ slower than for?

Yes, it's slower.


2 Answers

If you're using a C# version lower than 5.0 (where this was fixed), this is the reason:

The lambda in your query captures the loop variable vowel.
Because Linq likes to use deferred execution, the value of this reference is not read until the query gets executed (by iterating over it), which is after the foreach loop has finished. At that point, the most recent value of vowel is u, which is why you get the unexpected output.

You can get around this by copying the value to another temporary variable (or by upgrading to C# 5.0).

Try this:

query = "Probably what you might expect";  foreach (char vowel in "aeiou") {     char currentVowel = vowel;     query = query.Where (c => c != currentVowel ); } 
like image 136
Botz3000 Avatar answered Oct 08 '22 10:10

Botz3000


It's because you create a closure over the vowel variable, which changes in time. Store its value in a separate variable and it will work:

query = "Not what you might expect";  foreach (char vowel in "aeiou") {     var current = vowel;     query = query.Where (c => c != current); } 
like image 39
Honza Brestan Avatar answered Oct 08 '22 09:10

Honza Brestan