So I’m trying to learn more about lambda expressions. I read this question on stackoverflow, concurred with the chosen answer, and have attempted to implement the algorithm using a console app in C# using a simple LINQ expression.
My question is: how do I translate the “var result” of the lambda expression into a usable object that I can then print the result?
I would also appreciate an in-depth explanation of what is happening when I declare the outer => outer.Value.Frequency
(I’ve read numerous explanations of lambda expressions but additional clarification would help)
C#
//Input : {5, 13, 6, 5, 13, 7, 8, 6, 5}
//Output : {5, 5, 5, 13, 13, 6, 6, 7, 8}
//The question is to arrange the numbers in the array in decreasing order of their frequency, preserving the order of their occurrence.
//If there is a tie, like in this example between 13 and 6, then the number occurring first in the input array would come first in the output array.
List<int> input = new List<int>();
input.Add(5);
input.Add(13);
input.Add(6);
input.Add(5);
input.Add(13);
input.Add(7);
input.Add(8);
input.Add(6);
input.Add(5);
Dictionary<int, FrequencyAndValue> dictionary = new Dictionary<int, FrequencyAndValue>();
foreach (int number in input)
{
if (!dictionary.ContainsKey(number))
{
dictionary.Add(number, new FrequencyAndValue(1, number) );
}
else
{
dictionary[number].Frequency++;
}
}
var result = dictionary.OrderByDescending(outer => outer.Value.Frequency);
// How to translate the result into something I can print??
For the answer complete with print commands, see my answer here.
First off, the “lambda expression” is only the portion of the expression that is of the form
a=>b. The rest of your query is just a method call that takes a lambda as its argument.Anyway, if I could teach people one thing about LINQ it would be this: “result” isn’t the results of the query, it is the query itself.
If you want to see the results, ask the query for each result:
Sure. We begin by working out the types of everything involved. We see that the lambda is a function which takes a KeyValuePair and returns an int, so we generate a method
Next we take that method and create a delegate out of it:
and rewrite the extension method call:
and rewrite the var:
I hope you agree that the code you typed in is a whole lot more readable than this mess. Type inference rocks.
The result is an object which represents the ability to sort this dictionary by the given key. Read that carefully: it represents the ability to sort the dictionary by that key. It does not actually do that until you ask for a result; so far, all it is is an object that says “when asked for a result, sort the dictionary by this key”.
Suppose you ask for a result. How does it compute the sorted list? It asks the dictionary for each element. Then it calls MyLambda on each element, which gives back an integer, so we now have a pair of dictionary key-value pairs and integers. It then builds a list of pairs sorted on that integer. Then it hands out elements of that list one at a time, as you ask for them.
Ah, I see the confusion; for pedagogic reasons I fibbed a bit above regarding the exact order in which the semantic analysis proceeds.
How we do this type inference is one of the more subtle and interesting parts of C#.
Here’s how it works.
We see that OrderByDescending is declared as:
and we see we have a potential call to this method:
But we do not know what T and K are. So we start by looking at everything that is NOT a lambda. Your dictionary implements
IEnumerable<KeyValuePair<int, FrequencyOrValue>>so we start by saying “T is probablyKeyValuePair<int, FrequencyOrValue>“.At this point there is nothing else we can deduce from stuff that is not lambdas so we start looking at the lambdas. We see that we have a lambda
o=>o.Value.Frequencyand so far we have determined that the type of keyExtractor isFunc<KeyValuePair<int, FrequencyOrValue>, K>and we are still looking for K. So we say suppose the lambda actually was:And we ask does it bind? YES! Yes it does. We can successfully compile this lambda without error and when we do so, we see that all of its return statements return an int.
Therefore we deduce that K is int, and we now have a full type analysis of the whole thing.
This is a fairly straightforward inference; they can get much weirder. See the “type inference” archive on my blog if this subject particularly interests you.
http://blogs.msdn.com/ericlippert/archive/tags/Type+Inference/default.aspx
In particular, here’s a video of me explaining the stuff above plus a few other interesting cases:
http://blogs.msdn.com/ericlippert/archive/2006/11/17/a-face-made-for-email-part-three.aspx