Is there a better way to write this? I feel like I'm getting rusty with C# after doing a lot of JavaScript lately. Can this be improved?
foreach (var item in this.CartItems)
{
if (item.EffectivePrice != null)
{
this.CartItems[this.CartItems.IndexOf(item)].EffectivePrice =
CurrencyHelper.GetLocalizedCurrency(item.EffectivePrice);
}
}
Well, you could write it in LINQ query syntax with a from and a where, but I'm not sure it is a big change; I'd be more interested in knowing if the lookup is unnecessary:
this.CartItems[this.CartItems.IndexOf(item)].EffectivePrice =
CurrencyHelper.GetLocalizedCurrency(item.EffectivePrice);
to:
item.EffectivePrice = CurrencyHelper.GetLocalizedCurrency(item.EffectivePrice);
Other than that, I'm not sure it is worth the bother of changing it; I'd probably leave it as:
foreach (var item in this.CartItems) {
if (item.EffectivePrice != null) {
item.EffectivePrice = CurrencyHelper.GetLocalizedCurrency(item.EffectivePrice);
}
}
Straight up answer to your question (about how to implement your code in Linq):
this.CartItems.Where(item => item.EffectivePrice != null).ToList().ForEach
(
item =>
item.EffectivePrice = CurrencyHelper.GetLocalizedCurrency(item.EffectivePrice);
);
There is no reason to have to explicitly specify the index of the item in the list (at least I haven't seen a reason). The .ToList() gives you a List<T> of object references for you to manage. You AsQueryable() to save a few CPU cycles.
It's a little strange, however, to overwrite a property with the results of the method call as subsequent method calls on that property may alter the value over and over again.
But, nonetheless, Linq's method is far more elegant. The drawback, that I can see, is the inability to edit-and-continue with any method that contains Linq.
I think you can do something like this:
foreach (var item in this.CartItems.Where(i => i.EffectivePrice != null))
{
item.EffectivePrice =
CurrencyHelper.GetLocalizedCurrency(item.EffectivePrice);
}
In addition to Marc's point, LINQ is more for functional(ish) stuff, and isn't so helpful at mutating existing data structures. Which is a good thing. So if you wanted to produce a new array of new objects, you'd go with something like:
var newItems = CartItems
.Select(i => CreateNewItemWithPrice(i, item.EffectivePrice ??
CurrencyHelper.GetLocalizedCurrency(item.EffectivePrice))
.ToList();
In general, that's a very nice approach, since mutating data can cause an awful lot of bugs.
Related
I'm trying to find the fastest and most performant way to select a subset of items from a list based on a key property and assign this subset (list) to the property of an item in another list. The performance side of this is important since this part of code is going to be invoked very often each workday. I measured the performance in ticks to clearly see the relative difference.
I've got two lists (example setup);
List<CategorySetting> catList;
List<Customer> custList;
The CategorySetting entity has a property called SettingsId. The Customer entity has a SettingsId property as well, which is in fact a foreign key from Customers to CategorySetting.
The first piece of code i wrote was the most straight forward;
// normal for each: 13275 ticks
foreach (var catItem in catList)
{
catItem.Customers = custList.Where(c => c.SettingsId == catItem.SettingsId).ToList();
}
This would take about 13275 ticks.
I then thought maybe using parallelism this could be a lot faster? So I wrote this piece of code;
// parallel for each: 82541 ticks
Parallel.ForEach(catList, catItem =>
{
catItem.Customers = custList.Where(c => c.SettingsId == catItem.SettingsId).ToList();
});
This took way longer; 82541 ticks. That made no sense to me because of the parallel nature of this approach. It should use multiple threads to do this so in theory should be much faster. Then I started wondering what would happen if the multiple threads would try to access the customerlist at the same time. That might result in locks and queues hence taking more time because of the overhead? The same as for the writing to the main list.
I tried another approach. I made a ConcurrentBag for the catList (main list).
ConcurrentBag<CategorySettings> csBag = new ConcurrentBag<CategorySettings>(catList);
The custList I punt into a ConcurrentDictionary already grouped by the SettingsId.
var dict = custList.GroupBy(c => c.SettingsId).ToDictionary(x => x.Key, y => y.ToList());
ConcurrentDictionary<int?, List<Customer>> concDict = new ConcurrentDictionary<int?, List<Customer>>(dict);
The final try was then like this:
// paralell, bag, concurrent dictionary: 40255
Parallel.ForEach(caBag, ca =>
{
concDict.TryGetValue(ca.SettingsId, out var selCust);
ca.Customers = selCust;
});
This would take 40255 ticks. Can anyone explain why this is still taking longer? And more important is there no other way then 'just' a foreach loop? Feels like i'm missing something here.
Any ideas are greatly appreciated!
You could try using the ToLookup LINQ method:
var customersLookup = custList.ToLookup(item => item.SettingsId);
foreach (var catItem in catList)
{
catItem.Customers = customersLookup[catItem.SettingsId].ToList();
}
I assumed that the CategorySetting class has a writable property Customers of type IList<Customer>. In case the property is of type IEnumerable<Customer>, you could omit the ToList call.
I ended up using what I had;
foreach (var catItem in catList)
{
catItem.Customers = custList.Where(c => c.SettingsId == catItem.SettingsId).ToList();
}
#NetMage pointed out very well that this is probably useless optimalisation. I figured that the paralell foreach would be of major use here, but no matter what, the first loop was still the fastest. Both on my quadcore and on my xeon.
I have a List<Email>() and my Email object looks like this:
public class Email
{
public string EmailAddress { get; set; }
public bool IsPrimary { get; set; }
}
When I add a new email address that is set as primary, I want to set all the others as non-primary. I currently handle this using a foreach. Can I handle this using LINQ?
My current code is:
foreach (var item in emails)
{
if(item.EmailAddress.ToLower() != newEmailAddress.ToLower() && item.IsPrimary)
item.IsPrimary = false;
}
Linq queries collections, it doesn't modify them. The only spot in this equation that linq would come into play is actually making it a part of the enumeration - filtering the collection you're iterating over rather than doing an if statement inside it.
foreach (var item in emails.Where(e => e.IsPrimary && !e.EmailAddress.Equals(newEmailAddress, StringComparison.InvariantCultureIgnoreCase)))
{
item.IsPrimary = false;
}
EDIT: I didn't originally include it as it's not LINQ and that's what the question is about, but as mentioned in the comments on your question List<T> does include a ForEach method.
It would look like this:
emails.ForEach(item =>
{
item.IsPrimary = item.IsPrimary && item.EmailAddress.Equals(newEmailAddress, StringComparison.InvariantCultureIgnoreCase);
});
LINQ is intended for querying and not modification. Having said that, there is a List.ForEach operator, but with no increase in readability most of the time.
Having said that, I personally prefer not having side effect causing code that modifies the collection but I am not opposed to modifying the objects in the collection.
Add an extension method on IEnumerable to encapsulate the foreach loop:
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) {
foreach (var s in source)
action(s);
}
Then you can re-write your code as follows:
emails.Where(item => item.IsPrimary && !item.EmailAddress.Equals(newEmailAddress, StringComparison.InvariantCultureIgnoreCase))
.ForEach(item => item.IsPrimary = false);
(Thanks to #McAden for the better string comparison I always forget.)
However, since you are creating a race condition anyway, if practical I would suggest reversing your order of operations:
// before adding newEmailAddress
emails[emails.FindIndex(item => item.IsPrimary)].IsPrimary = false; // add error handling if it is possible no `IsPrimary` exists.
// now assign the newEmailAddress and set that item.IsPrimary to true
You can easily do that, but you should not as no one would expect LINQ code to modify the items in the collection.
emails
.Where(item =>
(item.EmailAddress.ToLower() != newEmailAddress.ToLower() && item.IsPrimary)
.Select(item => { item.IsPrimary = false; return true;})
.All();
Note that since LINQ queries are actually executed when result is enumerated you need something that will actually enumerate result. I.e. .All() call.
What would happen after you write this code - someone (or you in a week) remove that stupid and pointless .All() call at the end and things will be somewhat
ok, but modification no longer happen, person will spend a day sorting it out and then use some words to describe author of the code. Don't go there.
I saw this loop in test code:
foreach ( StuffId Id in Result.GetIdList() )
{
if ( Id.Level == 3 )
{
Level3Id = Id.ToString();
}
if ( Id.Level == 5 )
{
Level5Id = Id.ToString();
}
}
Other tests imply that either there is only one Id for each level or when there are multiples for each level then the Id will be the same.
Being slightly obsessed with LINQ right now, I first refactored to this:
IEnumerable<StuffId> Ids = Result.GetIdList();
Level3Id = Ids.Where( x => x.Level == 3 ).First().Id.ToString();
Level5Id = Ids.Where( x => x.Level == 5 ).First().Id.ToString();
Then the code repetition bothered me so I refactored to this:
IEnumerable<StuffId> Ids = Result.GetIdList();
Func<int,string> IdFromLevel =
level => Ids.Where( x => x.Level == level ).First().Id.ToString();
Level3Id = IdFromLevel(3);
Level5Id = IdFromLevel(5);
A colleague wondered why I didn't use a method in place of the delegate. My reasoning is a method would be slightly more 'messy' because I'd have to additionally pass in the collection and that using a delegate is no big deal for a simple test (for which terse, readable and no branching are good qualities).
I had a look on SO, of course, and found this seemingly relevant question:
C#: Func<> instead of methods?
where the consensus seems to favour a method over a delegate. Does the same apply in my case?
It is a question of reuse. If you are using methods that might be reusable in other cases, you should define them seperately.
But if you have only short statements that additionally vary, you should stick with anonymous functions/lambda-expressions, these might result in a better runtime-behavior.
From SO:
There is no advantage in the code you posted. In your code, using the delegate just adds complexity as well as an extra runtime cost - so you're better off just calling the method directly.
However, delegates have many uses. "Passing around" to other methods is the primary usage, though storing a function and using it later is also very useful.
LINQ is built on top of this concept entirely. When you do:
var results = myCollection.Where(item => item == "Foo");
You're passing a delegate (defined as a lambda: item => item == "Foo") to the Where function in the LINQ libraries. This is what makes it work properly.
Not sure about pros and cons, but reading these articles might help you to take a better decision:
http://msdn.microsoft.com/en-in/library/bb549151.aspx
http://msdn.microsoft.com/en-us/library/orm-9780596516109-03-09.aspx
http://msdn.microsoft.com/en-in/library/98dc08ac.aspx
I would go with the first block:
foreach (StuffId Id in Result.GetIdList())
{
if (Id.Level == 3)
{
Level3Id = Id.ToString();
}
if (Id.Level == 5)
{
Level5Id = Id.ToString();
}
}
This does loop the collection only once. I see you don't worry about performance here, but for me its not a matter of performance or optimization. It's a matter of doing something logically correct way. Why do something twice if it could be in one step (provided readability is not hurt).
The added benefit is that you don't have the dilemma between Func<,> and method, and the related complexities. As far as number of characters or ease of typing goes, its almost the same, except you're writing it horizontally (in the second case) than vertically. You can even write the above in two lines inside the foreach block.
If you're bent on writing the two actions separately, I would make the choice based on whether the function has relevance outside the scope of current method in this case. It seems to me that its a trivial predicate which is relevant only for the two assignments. So I like:
var Ids = Result.GetIdList();
Func<int, string> IdFromLevel = level => Ids.Single(x => x.Level == level).Id.ToString();
Level3Id = IdFromLevel(3);
Level5Id = IdFromLevel(5);
Prefer Single here over First..
what method of populating a drop down list is more efficient?
var info = db.table.Where( x => x.column == targetInformation).
Select(x => new {x.item, x.index});
**************FOREACH
foreach( var infos in info)
{
drowDownList.Items.Add(new {infos.item,infos.index.ToString()});
}
**************DATABIND
dropDownList.DataSource = info;
dropDownList.DataBind();
As stated by John Saunders, the efficiency here is not really something to consider especially considering the use of DB operations.
In other words, the performance of each is going to be very nearly the same.
What you should consider, though, is what is more efficient for you as a programmer to read? Also, are you going to be sharing this code with others on a team? Are they more used to WPF-style code, or the more manual style of code?
Perhaps the best efficiency to go for in this case is to maximize the readability of this code for you and your coworkers.
This is a little different, but you can try something like this:
var results = table.AsEnumerable().Where(row => row.Field<int>("SomeType") > 1);
foreach (DataRow row in results)
{
dropDownList.Items.Add(row.Field<string>("SomeText"), row.Field<int>("SomeID"));
}
//you don't need to databind if you're adding the items manually
//dropDownList.DataSource = info;
//dropDownList.DataBind();
for example
foreach (var item in List<int> a)
{
b.add(item);
c+=item;
dosomething();
}
how to write this into Linq form? or is it necessary?
I guess it has the following format: var b = a.xxxx(x=>(c+=x;dosomething())).ToList()
Since LINQ is really intended to be a query language, I would say it's bad style to have queries that have secondary effects when they are evaluated. I'd personally either leave things the way they are, or change it to something like this:
var c = a.Sum();
var b = a.ToList();
foreach(var item in a)
{
DoSomething();
}
Even though you end up iterating over the list multiple times, it's much easier to glance at each line of code and know immediately what it does.
You could do this:
var b = a.Select(i => { c += i; dosomething(); return i; }).ToList();
Note that this is probably considered bad practice. The foreach loop is likely more readable and therefore more maintainable. (It will also be more performant, since there isn't a jump-to-pointer instruction being executed for each item in the list.)