HasNext, or the like, for Dictionary iterator

  • Thread starter Thread starter sasha
  • Start date Start date
S

sasha

Basically, I am iterating over KeyValue pair of Dictionary. I need
to call some function when there is no next element in the dictionary:
something like this:

foreach (KeyValuePair<int, Object> kvp in MyDictionary)
{
//....do something
if(There is no next element)
call some function

}

I don't want to directly use the iterators, how would suggest to
approach this problem?


Thanks
 
sasha said:
Basically, I am iterating over KeyValue pair of Dictionary. I need
to call some function when there is no next element in the dictionary:
something like this:

foreach (KeyValuePair<int, Object> kvp in MyDictionary)
{
//....do something
if(There is no next element)
call some function

}

I don't want to directly use the iterators, how would suggest to
approach this problem?
Directly use the iterator.

It's either that or become a Zen master and learn how to speak of things
without mentioning them.
 
There are lots of possibilities, some more efficient than others.  My  
preferred approach would be simply to restructure the loop so that you can  
perform that "last element" work outside the loop.  For some loops, this  
is very easy, but even in the worst-case you might wind up with something 
like this:

     KeyValuePair<int, object> kvpPrev = null;

     foreach (KeyValuePair<int, object> kvp in MyDictionary)
     {
         if (kvpPrev != null)
         {
            // do stuff
         }

         kvpPrev = kvp;
     }

     if (kvpPrev != null)
     {
         // do stuff, including stuff for the last element
     }

The pattern can be made simpler and more maintainable by creating an  
anonymous method that can be called in both places (so you only have to  
maintain one copy of the loop body):

     KeyValuePair<int, object> kvpPrev = null;
     Action<bool> actionLoop = delegate(bool fLast)
         {
             // do stuff

             if (fLast)
             {
                 // do stuff for last element
             }

             // do other stuff
         };

     foreach (KeyValuePair<int, object> kvp in MyDictionary)
     {
         if (kvpPrev != null)
         {
             kvpPrev(false);
         }

         kvpPrev = kvp;
     }

     if (kvpPrev != null)
     {
         kvpPrev(true);
     }

Other methods include keeping a counter and comparing it to the count of  
elements in the dictionary so you know when you're at the end, or even (as  
Jeroen suggests) go ahead and use the iterator directly.

Pete

Thanks Guys, I did something simpler in terms of complexity:

int totaPairs = 0;
foreach (KeyValuePair<int, object> kvp in MyDictionary)
{
if(++totalPairs==MyDictionary.Count)
{
//do something... MyDictionary doesn't change during
the iteration, hence count remains the same during the loop
execution.
}

}

Any issues with that in a single threaded environment where Dictionary
will not change?

Thanks
 
KeyValuePair<TKey, TValue> is a structure, so any of the solutions that
use null as a marker isn't going to work without some reworking. I'd
recommend creating an iterator which converts from KeyValuePair<int, object>
to KeyValuePair<int, object>?:

// You might need to do some work in the lambda passed to Select.
IEnumerable<KeyValuePair<int, object>?> nullableKvps = MyDictionary.Select(x
=> x);

You could work it further to have a static extension method which will
convert IEnumerable<T> to an IEnumerable<T?> and then append the null
element at the end to serve as your (the OP's) "marker".
 
    KeyValuePair said:
use null as a marker isn't going to work without some reworking.  I'd
recommend creating an iterator which converts from KeyValuePair<int, object>
to KeyValuePair<int, object>?:

// You might need to do some work in the lambda passed to Select.
IEnumerable<KeyValuePair<int, object>?> nullableKvps = MyDictionary.Select(x
=> x);

    You could work it further to have a static extension method whichwill
convert IEnumerable<T> to an IEnumerable<T?> and then append the null
element at the end to serve as your (the OP's) "marker".

I would like to see how it can be implemented with Lambada and
extension methods. I am fairly new to these features... hope I am not
asking too much
thanks,
 
Yes, I definitely didn't mean to imply it would be a great task. It is
simple enough.
 
Back
Top