tags:

views:

103

answers:

6

I have a dictionary which I need to keep updated with incoming data, after parsing the incoming data I have to check if there are any entries in the dictionary which are not present in the incoming data (incoming data when parsed is a list and I need to map it with the dictionary entries).

To avoid multiple loops to removed the entries, I ran a decrementing for loop for dictionary count, then I fetch the dictionary key of the index using ElementAt, then check if the entry is present in the incoming data if not then I remove that entry from the list. I did this because running the foreach loop on the dictionary keys and removing from it will raise and exception as the dictionary keys collection would be modified.

I wanted to understand that doing this will there be any impact on execution time. I want to understand what is the order of ElementAt operation.

+1  A: 

I think that ElementAt() uses the enumerator to get to the required element.

It will be the same as:

object returnedElement = null;
int i = 0;
foreach (var obj in dictionary.Keys)
{
   if (i++ == at)
    {
      returnedElement = obj;
      break;
    }
}
Itay
Thanks! Itay for your response I found that it does use Enumerator
bjoshi
+1  A: 

ElementAt() does use the enumerator as pointed out, so if you want fastest index access you should use an array. Of course, that comes at the price of a fixed length, but if the size of the array is not constantly changing, it is feasible that Array.Resize() might be the way to go.

danijels
I can do that but I also have the task of mapping with the incoming data, that means I will have to have sorted array and again I have to expose it as a collection so that will require a copy operation I guess which will be expensive. Correct me if I am wrong here.
bjoshi
Not sure why you would need a copy. Array implements both ICollection and IEnumerable so it should be fine.
danijels
+2  A: 

Use "mark then remove" trick as a workaround for inability to modify collection while iterating.

    Dictionary<int, string> dict = new Dictionary<int, string>
    { 
        {3, "kuku" },
        {1, "zOl"}
    };

    List<int> data = new List<int> { 1, 2, 4 };

    List<int> toRemove = dict.Keys.Where(k => !data.Contains(k)).ToList();

    foreach (int k in toRemove)
        dict.Remove(k);

    foreach (var p in dict)
        Console.WriteLine(p);
Grozz
yes I did that previously and then changed to ElementAt, I wanted to know the best way to do that for optimal performance. I was profiling found that this is faster than ElementAt as Itay and danijels pointed our it does use enumerator, taking up extra time.
bjoshi
ElementAt for Dictionary seems to be O(log n) operation which isn't too slow. But I guess it adds up.
Grozz
+1  A: 

ElementAt is useful if you need to provide indexing semantics and cannot guarantee that indexing semantics will be available in the underlying enumeration. It does use O(1) indexing when the enumeration acted upon is an IList<T> (which includes List and arrays), but otherwise is O(n), which makes it being used in a sequence over everything go from the O(n) operation it would be with a list to O(n * n).

If however you got a copy of the keys with dict.Keys.ToList() then you could safely foreach through that, as it won't be changed by changes to your dictionary.

What isn't clear is why you don't just replace the old dictionary with the new one, which would be considerably faster again (simple reference assignment).

Jon Hanna
Thanks! I was refactoring some code already present and then got confused to miss some obvious ways
bjoshi
A: 

You can get a Dictionary of the matching entries in target (Dictionary) and source (List) as follows:

using System;
using System.Collections.Generic;
using System.Linq;

Dictionary<string, string> target = new Dictionary<string, string>();
List<string> source = new List<string>();
target.Add("a", "this is a");
target.Add("b", "this is b");
source.Add("a");
source.Add("c");

target = Enumerable.Select(target, n => n.Key).
    Where(n => source.Contains(n)).ToDictionary(n => n, k => target[k]);

It's not clear to me if you want to include new entries from the List into the Dictionary - if so, I am not sure what the new entry values would be if you only have a List of new incoming data.

Steve Townsend
+1  A: 

Except() seems like it would work here:

Dictionary<int, string> dict = new Dictionary<int, string>
{ 
    {3, "kuku" },
    {1, "zOl"}
};

IEnumerable<int> data = new List<int> { 1, 2, 4 };

IEnumerable<int> toRemove = data.Except(dict.Keys);

foreach(var x in toRemove)
    dict.Remove(x);
dahlbyk