This question already has answers here:
C# Lambda expressions: Why should I use them?
(17 answers)
Closed 9 years ago.
Can anyone give me a good explanation of how to use Lambda and give a good example. I have seen it but I dont know what it is or does.
A lambda expression is used to create an anonymous function. Here an anonymous function is assigned to a delegate variable:
Func<int, int> increase = (a => a + 1);
You can then use the delegate to call the function:
var answer = increase(41);
Usually lambda expressions are used to send a delegate to a method, for example sending a delegate to the ForEach method so that it's called for each element in the list:
List<int> list = new List<int>();
list.Add(1);
list.Add(2);
list.ForEach(n => Console.WriteLine(n));
I did a post a while back which I hope may be of some use: http://www.dontcodetired.com/blog/?tag=/lambda+expressions
A Lambda is simply a delegate, its an anonymous function that you can create for later execution.
A Lambda Expression is an uncompiled delegate in the form of an Expression Tree that you can manipulate before compiling and executing.
http://msdn.microsoft.com/en-us/library/bb397687.aspx
Perhaps I'm being a bit simplistic, but, if I were you, to start with I'd just consider lambdas as a nice way to shorten code by removing things like nested foreach loops or top n elements.
So if you're running round hotels to find some with cheap rooms you could (assuming hotels in IEnumerable):
cheapHotels = hotels.Where(h => h.PriceFrom < 50)
Once this starts to click you can move onto something more complex, this is a random method that I can find in my current project using lambdas (probably nicked from somewhere else!):
private T DeserializeObject<T>(XmlDocument xDoc, string typeName)
{
Type type = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Single(t => t.FullName == typeName);
object o;
var serializer = new XmlSerializer(typeof(T));
using (TextReader tr = new StringReader(xDoc.InnerXml))
{
o = serializer.Deserialize(tr);
tr.Close();
}
return (T)o;
}
Related
I'm trying to convert some JS into C# and i got to this piece but cant figure out what a C# equivalent would be. Hoping someone can point me in the right direction?
I just need help with the contents of these two functions. The $iterator is coded in another spot but im guessing that the C# version of the following code doesnt need it. If you need me to add it, i can.
The context these functions are being called is:
var centers = Lambda.array(Lambda.map(this.hexes,function(hex) {
return me.hexToCenter(hex);
}));
And the functions are:
var Lambda = function() { }
Lambda.array = function(it) {
var a = new Array();
var $it0 = $iterator(it)();
while( $it0.hasNext() ) {
var i = $it0.next();
a.push(i);
}
return a;
}
Lambda.map = function(it,f) {
var l = new List();
var $it0 = $iterator(it)();
while( $it0.hasNext() ) {
var x = $it0.next();
l.add(f(x));
}
return l;
}
You don't really need your own map and array methods. There is already the same functionality available, you just have to add using System.Linq; at the top of your file and you'll be able to use both Select, which is a projection method and ToArray which created an array from your collection. They are both extension methods set on IEnumerable<T>, so you can use them on almost any collection.
var centers = hexes.Select(x => me.hexToCenter(x)).ToArray();
is an equivalent of you JavaScript code:
var centers = Lambda.array(Lambda.map(this.hexes,function(hex) {
return me.hexToCenter(hex);
}));
This looks like a fairly simple C# lambda:
var centers = this.hexes.Select(hex => me.hexToCenter(hex)).ToList();
Select and ToList extension methods are provided by LINQ - you need to add using System.Linq to use them.
You probably want to go the LINQ route here.
Your map is equivalent to LINQ's Select, e.g.
var centers = this.hexes.Select(hex => me.hexToCenter(hex)).ToArray();
The expression hex => me.hexToCenter(hex) is a lambda expression in C#, which Select uses to project this.hexes into your desired form.
ToArray() is equivalent to your Lambda.array call.
101 LINQ Samples in C# is a great resource for examples on using LINQ.
note most of the 101 samples use the query syntax as opposed to the functional syntax I've used above. They are roughly equivalent for simple cases, but being comfortable with the functional syntax shouldn't be a problem for you, coming from JS background.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C# Syntax - Example of a Lambda Expression - ForEach() over Generic List
I would like to simplify my code and change it to something shorter and still readable code.
List<string> onlineModelsNumbers = new List<string>();
foreach (OnlineModel om in OnlineModels)
onlineModelsNumbers.Add(om.model_id.ToString());
Here I'm thinking about writing the same thing in a lambda expression. But how do I do that?
List<string> onlineModelsNumbersL = onlineModelsNumbers.ForEach(...)
or
List<string> onlineModelsNumbersL = new List<string>(onlineModelsNumbers.ForEach(...))
Any other suggestions?
List<string> onlineModelsNumbers = OnlineModels.Select(om => om.model_id.ToString()).ToList();
How about:
onlineModelsNumbers.AddRange(OnlineModels.Select(o => o.model_id.ToString());
var onlineModelsNumbers = OnlineModels.Select(m => m.model_id.ToString())
.ToList();
LINQ purposely does not come with a ForEach extension (so that LINQ functions remain pure) but it is easy to write your own that wraps a foreach.
Your code is already simple. You could consider using an implicitly-typed loop variable:
foreach(var om in OnlineModels)
{
onlineModelNumbers.Add(om.model_id.ToString());
}
Or you could use AddRange:
onlineModelNumbers.AddRange(OnlineModels.Select(om => om.model_id.ToString()));
You don't need a foreach here, select will do that for you:
IEnumerable<string> = OnlineModels.Select(x => x.model_id.ToString());
Just transform and add it as a range:
List<string> onlineModelsNumbers = new List<string>(OnlineModels.Select(om => om.model_id.ToString()));
You want to perform your "foreach" on every member of OnlineModels, and as a result want to add the model's model_id string representation to onlineModelsNumbers.
I'd expect to write the expressions as follows:
onlineModels.ForEach(om => onlineModelsNumbers.Add(om.model_id.ToString()))
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Use of var keyword in C#
Being relatively new to C# I was wondering the motivation MS had to introduce the var implicit typed variables. The documentation says:
An implicitly typed local variable is strongly typed just as if you
had declared the type yourself, but the compiler determines the type.
Some lines further:
In many cases the use of var is optional and is just a syntactic
convenience
This is all nice but in my mind, this will only cause confusion.
Say you are reviewing this for loop.
foreach (var item in custQuery){
// A bench of code...
}
Instead of reviewing the content and the semantics of the loop, I would loose precious time looking for the item's type!
I would prefer the following instead:
foreach (String item in custQuery){
// A bench of code...
}
The question is: I read that implicit typed variables help when dealing with LINQ, does really help to use it in other scenarios?
The var keyword was needed when LINQ was introduced, so that the language could create a strongly typed variable for an anonymous type.
Example:
var x = new { Y = 42 };
Now x is a strongly typed variable that has a specific type, but there is no name for that type. The compiler knows what x.Y means, so you don't have to use reflection to get to the data in the object, as you would if you did:
object x = new { Y = 42 };
Now x is of the type object, so you can't use x.Y.
When used with LINQ it can for example look like this:
var x = from item in source select new { X = item.X, Y = item.Y };
The x variable is now an IEnumerable<T> where T is a specific type which doesn't have a name.
Since the var keyword was introduced, it has also been used to make code more readable, and misused to save keystrokes.
An example where it makes the code more readable would be:
var list =
new System.Collections.Generic.List<System.Windows.Forms.Message.Msg>();
instead of:
System.Collections.Generic.List<System.Windows.Forms.Message.Msg> list =
new System.Collections.Generic.List<System.Windows.Forms.Message.Msg>();
This is a good use of the var keyword, as the type already exists in the statement. A case where the keyword can be misused is in a statement like:
var result = SomeMethod();
As the SomeMethod name doesn't give any indication of what type it returns, it's not obvious what the type of the variable will be. In this case you should write out the type rather than using the var keyword.
I think some of the motivation was to allow something like this -
List<int> list = new List<int>();
to be turned into this -
var list = new List<int>();
The second example is shorter and more readable, but still clearly expresses the intent of the code. There are instances when it will be less clear, but in lots of situations you get conciseness with no loss of clarity.
var is really needed for anonymous types, which are used in Linq a bit:
var results =
from item in context.Table
select new {Name=item.Name, id=item.id};
Since the collection is of an anonymous type, it can not be named. It has a real type, but not one with a name before compilation.
I am trying to parallelize a query with a groupby statement in it. The query is similar to
var colletionByWeek = (
from item in objectCollection
group item by item.WeekStartDate into weekGroups
select weekGroups
).ToList();
If I use Parallel.ForEach with shared variable like below, it works fine. But I don't want to use shared variables in parallel query.
var pSummary=new List<object>();
Parallel.ForEach(colletionByWeek, week =>
{
pSummary.Add(new object()
{
p1 = week.First().someprop,
p2= week.key,
.....
});
}
);
So, I have changed the above parallel statement to use local variables. But the compiler complains about the source type <IEnumerable<IGrouping<DateTime, object>> can not be converted into System.Collections.Concurrent.OrderablePartitioner<IEnumerable<IGrouping<DateTime, object>>.
Am I giving a wrong source type? or is this type IGouping type handled differently? Any help would be appreciated. Thanks!
Parallel.ForEach<IEnumerable<IGrouping<DateTime, object>>, IEnumerable<object>>
(spotColletionByWeek,
() => new List<object>(),
(week, loop, summary) =>
{
summary.Add(new object()
{
p1 = week.First().someprop,
p2= week.key,
.....
});
return new List<object>();
},
(finalResult) => pSummary.AddRange(finalResult)
);
The type parameter TSource is the element type, not the collection type. And the second type parameter represents the local storage type, so it should be List<T>, if you want to Add() to it. This should work:
Parallel.ForEach<IGrouping<DateTime, object>, List<object>>
That's assuming you don't actually have objects there, but some specific type.
Although explicit type parameters are not even necessary here. The compiler should be able to infer them.
But there are other problems in the code:
you shouldn't return new List from the main delegate, but summary
the delegate that processes finalResult might be executed concurrently on multiple threads, so you should use locks or a concurrent collection there.
I'm going to skip the 'Are you sure you even need to optimize this' stage, and assume you have a performance issue which you hope to solve by parallelizing.
First of all, you're not doing yourself any favors trying to use Parallel.Foreach<> for this task. I'm pretty sure you will get a readable and more optimal result using PLINQ:
var random = new Random();
var weeks = new List<Week>();
for (int i=0; i<1000000; i++)
{
weeks.Add(
new Week {
WeekStartDate = DateTime.Now.Date.AddDays(7 * random.Next(0, 100))
});
}
var parallelCollectionByWeek =
(from item in weeks.AsParallel()
group item by item.WeekStartDate into weekGroups
select new
{
p1 = weekGroups.First().WeekStartDate,
p2 = weekGroups.Key,
}).ToList();
It's worth noting that there is some overhead associated with parallelizing the GroupBy operator, so the benefit will be marginal at best. (Some crude benchmarks hint at a 10-20% speed up)
Apart from that, the reason you're getting a compile error is because the first Type parameter is supposed to be an IGrouping<DateTime, object> and not an IE<IG<..,..>>.
This is a long shot, I know...
Let's say I have a collection
List<MyClass> objects;
and I want to run the same method on every object in the collection, with or without a return value. Before Linq I would have said:
List<ReturnType> results = new List<ReturnType>();
List<int> FormulaResults = new List<int>();
foreach (MyClass obj in objects) {
results.Add(obj.MyMethod());
FormulaResults.Add(ApplyFormula(obj));
}
I would love to be able to do something like this:
List<ReturnType> results = new List<ReturnType>();
results.AddRange(objects.Execute(obj => obj.MyMethod()));
// obviously .Execute() above is fictitious
List<int> FormulaResults = new List<int>();
FormulaResults.AddRange(objects.Execute(obj => ApplyFormula(obj)));
I haven't found anything that will do this. Is there such a thing?
If there's nothing generic like I've posited above, at least maybe there's a way of doing it for the purposes I'm working on now: I have a collection of one object that has a wrapper class:
class WrapperClass {
private WrappedClass wrapped;
public WrapperClass(WrappedClass wc) {
this.wrapped = wc;
}
}
My code has a collection List<WrappedClass> objects and I want to convert that to a List<WrapperClass>. Is there some clever Linq way of doing this, without doing the tedious
List<WrapperClass> result = new List<WrapperClass>();
foreach (WrappedClass obj in objects)
results.Add(new WrapperClass(obj));
Thanks...
Would:
results.AddRange(objects.Select(obj => ApplyFormula(obj)));
do?
or (simpler)
var results = objects.Select(obj => ApplyFormula(obj)).ToList();
I think that the Select() extension method can do what you're looking for:
objects.Select( obj => obj.MyMethod() ).ToList(); // produces List<Result>
objects.Select( obj => ApplyFormula(obj) ).ToList(); // produces List<int>
Same thing for the last case:
objects.Select( obj => new WrapperClass( obj ) ).ToList();
If you have a void method which you want to call, here's a trick you can use with IEnumerable, which doesn't have a ForEach() extension, to create a similar behavior without a lot of effort.
objects.Select( obj => { obj.SomeVoidMethod(); false; } ).Count();
The Select() will produce a sequence of [false] values after invoking SomeVoidMethod() on each [obj] in the objects sequence. Since Select() uses deferred execution, we call the Count() extension to force each element in the sequence to be evaluated. It works quite well when you want something like a ForEach() behavior.
If the method MyMethod that you want to apply returns an object of type T then you can obtain an IEnumerable<T> of the result of the method via:
var results = objects.Select(o => o.MyMethod());
If the method MyMethod that you want to apply has return type void then you can apply the method via:
objects.ForEach(o => o.MyMethod());
This assumes that objects is of generic type List<>. If all you have is an IEnumerable<> then you can roll your own ForEach extension method or apply objects.ToList() first and use the above syntax .
The C# compiler maps a LINQ select onto the .Select extension method, defined over IEnumerable (or IQueryable which we'll ignore here). Actually, that .Select method is exactly the kind of projection function that you're after.
LBushkin is correct, but you can actually use LINQ syntax as well...
var query = from o in objects
select o.MyMethod();
You can also run a custom method using the marvelous Jon Skeet's morelinq library
For example if you had a text property on your MyClass that you needed to change in runtime using a method on the same class:
objects = objects.Pipe<MyClass>(class => class.Text = class.UpdateText()).ToList();
This method will now be implemented on every object in your list. I love morelinq!
http://www.hookedonlinq.com/UpdateOperator.ashx has an extended Update method you can use. Or you can use a select statement as posted by others.