tags:

views:

563

answers:

2

I have a Dictionary and a List of keys to remove from the dictionary. This is my implementation right now:

var keys = (from entry in etimes
            where Convert.ToInt64(entry.Value) < Convert.ToInt64(stime)
            select entry.Key).ToList();

foreach (var key in keys)
{
    etimes.Remove(key);
    count--;
}

Is there something I can do the eliminate the foreach loop?

+4  A: 
var pruned = etimes.Where(entry => Convert.ToInt64(entry.Value) >= 
    Convert.ToInt64(stime)).ToDictionary(entry => entry.Key, 
        entry => entry.Value);

This statement simply filters the dictionary using the LINQ Where function to select which items to keep rather than those to remove (which then requires further code, as you showed). The ToDictionary converts thwe IEnumerable<KeyValuePair<TKey, TValue>> to the desire Dictionary<TKey, TValue> type, and is at least quite simple, if not terribly elegant or efficient due to the need to specify the two lambda expressions to select the key and value from a KeyValuePair (and then creating a new dictionary). Saying this, I don't really see it as a problem, especially if the dictionary is small and/or number of items being removed is large.

Noldorin
I wouldn't want to comment on the performance by the way - if you care about that, then test the two methods. I'm not sure your original solution using foreach would be *that much* faster.
Noldorin
I'm not worried about performance, there are only a few keys in the dictionary at any time. I'm just trying to get a better handle of LINQ. Thanks, this worked great.
scottm
This might be much more expensive than the simple for each loop because it will create a new dictionary. And I think it does not improve readability, too. So I would just stick with the for each loop and maybe move it to a (extension) method, but I see no win at all for the LINQ solution.
Daniel Brückner
@Daniel: This is probably true, though if the number of items being removed is relatively large (or the dictionary is relatively small), then I doubt the difference in speed will be too significant. @scotty2012: Glad it works for you, anyway.
Noldorin
@Daniel: That may be true, but in my example, I'm creating an additional List<string> and running the foreach loop.
scottm
A: 

Well, performance or readability issues aside, couldn't this also be done something like the following:

<Extension> void itemDelete(List l, object item) {
    l.Remove(item)
}

var keys = (from entry in etimes
        where Convert.ToInt64(entry.Value) < Convert.ToInt64(stime)
        select entry.Key).ToList();

keys.foreach(itemDelete());

Forgive my coding, I'm not 100% certain of the exact syntax (especially in C#); consider that pseudo-code. Note the addition of the new function, and the .foreach function on the end of the LINQ query. I know this would be possible in VB, i assume C# has something similar... if not you could always write your own .foreach extension. It may or may not improve anything, but it's an idea.

eidylon
Forgive me if this is a dumb question, but would you create this Extension method in a partial class? I'm still trying to come to grips with Extension methods and how you can use and create them.
Jagd
@Jagd: This is no reason whatsoever to use a partial class. Recommended practice is to declare them on their own within a *static class* and group extension methods into static classes of similar functionality.
Noldorin
In VB you create them in Modules, so ... I'd say listen to Noldorin's Best Practices.
eidylon