LINQ query to select based on property - c#

IEnumerable<MyClass> objects = ...
foreach(MyClass obj in objects)
{
if(obj.someProperty != null)
SomeFunction(obj.someProperty);
}
I get the feeling I can write a smug LINQ version using a lambda but all my C# experience is 'classical' i.e more Java-like and all this Linq stuff confuses me.
What would it look like, and is it worth doing, or is this kind of Linq usage just seen as showing off "look I know Linq!"

LINQ itself doesn't contain anything for this - I'd would use a normal foreach loop:
foreach (var value in objects.Select(x => x.someProperty)
.Where(y => y != null))
{
SomeFunction(value);
}
Or if you want a query expression version:
var query = from obj in objects
let value = obj.SomeProperty
where value != null
select value;
foreach (var value in query)
{
SomeFunction(value);
}
(I prefer the first version, personally.)
Note that I've performed the selection before the filtering to avoid calling the property twice unnecessarily. It's not for performance reasons so much as I didn't like the redundancy :)
While you can use ToList() and call ForEach() on that, I prefer to use a straight foreach loop, as per Eric's explanation. Basically SomeFunction must incur a side-effect to be useful, and LINQ is designed with side-effect-free functions in mind.

objects.where(i => i.someProperty != null)
.ToList()
.ForEach(i=> SomeFunction(i.someProperty))

Although it can be done with Linq, sometimes its not always necessary. Sometimes you lose readability of your code. For your particular example, I'd leave it alone.

One option is to use the pattern outlined in the book Linq In Action which uses an extension method to add a ForEach operator to IEnumerable<>
From the book:
public static void ForEach<T> (this IEnumerable<T> source, Action<T> func)
{
foreach (var item in source)
func(item)
}
Then you can use that like this:
(from foo in fooList
where foo.Name.Contains("bar")
select foo)
.ForEach(foo => Console.WriteLine(foo.Name));

LINQ is used to create a result, so if you use it to call SomeFunction for each found item, you would be using a side effect of the code to do the main work. Things like that makes the code harder to maintain.
You can use it to filter out the non-null values, though:
foreach(MyClass obj in objects.Where(o => o.someProperty != null)) {
SomeFunction(obj.someProperty);
}

You can move the if statement into a Where clause of Linq:
IEnumerable<MyClass> objects = ...
foreach(MyClass obj in objects.Where(obj => obj.someProperty != null)
{
SomeFunction(obj.someProperty);
}
Going further, you can use List's ForEach method:
IEnumerable<MyClass> objects = ...
objects.Where(obj => obj.someProperty != null).ToList()
.ForEach(obj => SomeFunction(obj.someProperty));
That's making the code slightly harder to read, though. Usually I stick with the typical foreach statement versus List's ForEach, but it's entirely up to you.

Related

What is optimized way of forloop

Which For Loop is better for performance likewise coding criteria
var totalCount = new List<int>();
Foreach
foreach(var student in StudentList)
{
var studentItem= student.DataContext as studentEntity;
if (studentItem!= null)
{
totalCount.Add(studentItem.Id);
}
}
ForEach
StudentList?.ForEach(student=>
{
var studentItem= student.DataContext as studentEntity;
if (studentItem!= null)
{
totalCount.Add(studentItem.Id);
}
});
my question is that in fast performance which loop is more correct.
If in my StudentList there are records around 1000 and above and I want
to perform logic manipulation in c# then which ForLoop is better for
Fast Perfomance
thank you in advance !!!
Let .Net do it for you, get rid of any loop:
https://msdn.microsoft.com/en-us/library/z883w3dc(v=vs.110).aspx
totalCount.AddRange(studentList);
It's more readable and (potentially) more efficient.
Edit: If totalCount and studentList have different types, add Select, e.g:
totalCount.AddRange(studentList.Select(student => student.Id));
They are pretty much the same in terms of optimization, you can check Eric Lippert's blog: “foreach” vs “ForEach”, where he talks about this and shows forEach internally.
public static void ForEach<T>(this IEnumerable<T> sequence, Action<T> action)
{
// argument null checking omitted
foreach(T item in sequence) action(item);
}
Another .NET (LINQ) approach for creating list from another list (one-liner for one liner fans)
var totalCount = studentList.ToList();
Another LINQ approach , when you have already existed items.
var totalCount = new List<int> { 1, 2 ,3 };
var all = totalCount.Concat(studentList).ToList();
Impossible to not stick to example, because performance could be achieved only when you know context of the problem.
In your updated example readable and fast enough approach could be
var totalCount =
StudentList.Select(student => student.DataContext as Entity)
.Where(entity => entity != null)
.Select(entity => entity.Id)
.ToList();

Set several class values using LINQ expression

I have the following two LINQ statements which set different values in the same item in a list
List<MyClass> myList = GetList();
myList.Where(x => x.Name == "someName").Select(x => x.MyArray = someList.ToArray()).ToList();
myList.Where(x => x.Name == "someName").Select( x => x.AnotherValue = GetValue()).ToList();
Is it possible to combine this so both are set in the one expression?
myList
.Where(x => x.Name == "someName")
.ToList()
.ForEach(x => {
x.MyArray = someList.ToArray();
x.AnotherValue = GetValue();
});
Why are you calling ToList() at the end of each of those expressions and discarding the result?
Also, Jon Skeet is right that this is an abuse of LINQ, and especially so in your original form: It's explicit that LINQ expressions aren't even necessarily expected to be fully enumerated. The fact that you needed those ToList() calls to make anything happen should have given you a grave and queasy sense that you were misusing a language feature. When you have to do something weird to use your chosen construct instead of the usual way of doing it, finish getting it to work (because weird is cool), and then go back and redo it the boring, lame way before you check it in.
What advantage do you see in the LINQ + ForEach() version above, compared to this version?
foreach (var x in myList.Where(x => x.Name == "someName"))
{
x.MyArray = someList.ToArray();
x.AnotherValue = GetValue();
}
The old-style loop version is shorter, instantly understandable because it's the default idiom, and IMO cleaner. You don't have to do everything with LINQ.
N.B., ForEach() isn't LINQ; it's a member of List<T>. That's why you have to call ToList() to use it.
Just use the lambda operator to pass an entire lambda expression defined inside a
{...} block:
myList.Where(x => x.Name == "someName").Select(x => { x.MyArray = someList.ToArray(); x.AnotherValue = GetValue(); return x;}).ToList();

Is a statement recalculated in every iteration when used in LINQ?

For instance
myEnumerable.Where(v => v != myDictionary["someKey"])
when this query is called is myDictionary["someKey"] statement executed (meaning that dictionary is queried for the key) or the result of myDictionary["someKey"]
is used after the first iteration?
The result of myDictionary["someKey"] will not be cached(*see edit below), it will be accessed on every item of myEnumerable. However, you can still cache it manually :
var someValue = myDictionary["someKey"];
myEnumerable.Where(v => v != someValue)
Also take note that, if you plan to iterate/access that IEnumerable multiple time, it is best to actualize it via ToList(). Or, the execution will be deferred every single time.
var query = myEnumerable.Where(v => v != myDictionary["someKey"]);
foreach (var item in query) { /* ... */}
foreach (var item in query) { /* ... */}
In the above example, the Where clause is executed twice.
EDIT: As #LucasTrzesniewski has pointed out, this is only stands true for LINQ-to-Objects. This is because the query is evaluated in memory. However, for LINQ-to-Entities, it gets a little bit different, as the query will be converted into SQL query and then executed in the database in order to avoid round trips.
Here's a really simple demo (and please, don't try this at home):
var myDictionary = new Dictionary<string,string>() { { "someKey", "someValue" } };
var myEnumerable = new List<string> { "someValue", "someOtherValue" };
var test = myEnumerable.Where(v => v == myDictionary["someKey"]);
foreach (var t in test)
{
Console.WriteLine(t);
myDictionary["someKey"] = "someOtherValue";
}
If myDictionary["someKey"] was only evaulated once, then changing the value of myDictionary["someKey"] wouldn't change anything. But if you run the code, you will see that it will echo both someValue and someOtherValue. If you comment out the line that changes the dictionary value, then you will only see someValue
As #Lucas Trzesniewski points out in the comments to the other answer, this applies to LINQ-to-objects. There are a number of important differences between LINQ-to-objects and LINQ-to-SQL.
The Lambda expression you supply to the Linq Where extension is simply a Func<> delegate. The method is executed for each item in the IEnumerable(of T), receiving the current item as a parameter. It doesn't do anything special other than that. Your code is somewhat similar similar to:
var myTempCollection = new List<MyClass>();
foreach(MyClass item in myEnumerable)
{
if (item != myDictionary["someKey"])
{
myTempCollection.Add(item);
}
}
var result = myTempCollection;
It depends on the QueryProvider implementation. For example, the ObjectQueryProvider used by Linq-to-objects will access it on every iteration. For Linq-to-entities, it will access it once and then send that value to the database server.

Can you set/update a value in real-time within a LINQ statement during iteration?

Based on a proposed answer to my other question here... is it possible to update a variable during LINQ enumeration so you can use it as part of a test?
For instance, is anything like this possible?
// Assume limitItem is of type Foo and sourceList is of type List<Foo>
// Note the faux attempt to set limitItemFound in the TakeWhile clause
// That is what I'm wondering.
sourceList.Reverse()
.TakeWhile(o => (o != limitItem) && !limitItemFound; limitItemFound = limitItemFound || (o == limitItem) )
.FirstOrDefault(o => ...);
This would make the search inclusive of limitItem.
For LINQ to Objects (which takes delegates) then you can, yes - using a statement lambda:
sourceList.Reverse()
.TakeWhile(o => {
... fairly arbitrary code here
return someValue;
})
.FirstOrDefault(o => ...);
I would strongly discourage you from doing this though. It will make it much harder to understand what's going on, because you're losing the declarative nature of idiomatic LINQ code.

Can I use linq to achieve the same thing this foreach loop does?

Here's the c# code that I have:
private double get806Fees (Loan loan)
{
Loan.Fee.Items class806;
foreach (Loan.Fee.Item currentFee in loan.Item.Fees)
{
if (currentFee.Classification == 806) class806.Add(currentFee);
}
// then down here I will return the sum of all items in class806
}
Can I do this using linq? If so, how? I have never used linq and i've read in several places that using linq instead of a foreach loop is faster... is this true?
Similar to some existing answers, but doing the projection in the query, to make the Sum call a lot simpler:
var sum = (from fee in loan.Items.Fees
where fee.Classification == 806
select fee.SomeValueToSum).Sum();
loan.Item.Fees.
Where(x => x.Classification == 806).
Sum(x => x.SomeValueProperty)
Whether it is faster or not is debatable. IMO, both complexities are the same, the non-LINQ version may be faster.
var q =
from currentFee in loan.Item.Fees
where currentFee.Classification == 806
select currentFee;
var sum = q.Sum(currentFee => currentFee.Fee);
private double get806Fees(Loan loan)
{
return load.Item.Fees.
Where(f => f.Classification == 806).
Sum(f => f.ValueToCalculateSum);
}
I'm assuming here that ValueToCalculateSum is also a double. If it's not then you have to convert it before it is returned.
All of the answers so far are assuming that you're summing up loan.Fees. But the code you actually posted calls Items.Add() to add each Item in loan.Fees.Items to an Items object, and it's that Items object (and not loan.Fees, which is also an Items object) that you say you want to sum up.
Now, if Items is just a simple collection class, then there's no need to do anything other than what people are suggesting here. But if there's some side-effect of the Add method that we don't know about (or, worse, that you don't know about), simply summing up a filtered list of Item objects might not give you the results you're looking for.
You could still use Linq:
foreach (Loan.Fee.Item currentFee in loan.Item.Fees.Where(x => x.Classification == 806)
{
class806.Add(currentFee);
}
return class806.Sum(x => x.Fee)
I'll confess that I'm a little perplexed by the class hierarchy implied here, though, in which the Loan.Item.Fees property is a collection of Loan.Fee.Item objects. I don't know if what I'm seeing is a namespace hierarchy that conflicts with a class hierarchy, or if you're using nested classes, or what. I know I don't like it.

Categories

Resources