I'm working on a problem where I need to provide one item at a time to the consumer and move the counter forward so next item and so on until ran out of items. I came up with first draft of code (see below). The underlying data structure contains a Dictionary which contains string as its key and hold another dictionary as its value, which holds object of type Entity.
I've a sense that I do need to maintain the state somehow, so I tried using yield return statement but not sure how to jell it together. Also I think using forearch/iterator may need adjustment since consumer will call GetNextItem() until it returns false(meaning run out of items).
private static Dictionary<string, Dictionary <uint,Entity>> dt;
private uint localCounter=0 , globalCounter = 0;
public Entity GetNextItem()
{
foreach (string key in dt.Keys )
{
if (MoveCounters(key)) //counter is moved, so process the next item
{
yield return dt[key][localCounter];
}
}
}
private bool MoveCounters(string key)
{
if (++globalCounter > dt.Count) return false; //hit the limit
if (++localCounter > dt[key].Count)
{
globalCounter++;
return true;
}
localCounter++;
return true;
}
}
public class Entity
{
Dictionary<string, string> dtValues; //contains values from CSV file.
}
You're failing to reset localCounter
to zero when you move to the next sublist.
That said, you can do this so much easier:
foreach (var subdt in dt.Values)
foreach (var item in subdt.Values)
yield return item;
But it's even easier using LINQ SelectMany
return dt.Values.SelectMany(subdt => subdt.Values);
Note that the last one does not use yield return
, since LINQ produces the enumerable and you just return it.
If you want to log the keys and counters as well, try something like:
int iList = 0;
foreach( var subdt in dt ) {
/* log iList, subdt.Key */
int iItem = 0;
foreach( var item in subdt.Value ) {
/* log iItem, item.Key */
++iItem;
yield return item.Value;
}
++iList;
}