Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the pattern to use for iterating over associated sets of values?

Tags:

c#

iteration

linq

It's pretty common - especially as you try to make your code become more data-driven - to need to iterate over associated collections. For instance, I just finished writing a piece of code that looks like this:

string[] entTypes = {"DOC", "CON", "BAL"};
string[] dateFields = {"DocDate", "ConUserDate", "BalDate"};
Debug.Assert(entTypes.Length == dateFields.Length);

for (int i=0; i<entTypes.Length; i++)
{
    string entType = entTypes[i];
    string dateField = dateFields[i];
    // do stuff with the associated entType and dateField
}

In Python, I'd write something like:

items = [("DOC", "DocDate"), ("CON", "ConUserDate"), ("BAL", "BalDate")]
for (entType, dateField) in items:
   # do stuff with the associated entType and dateField

I don't need to declare parallel arrays, I don't need to assert that my arrays are the same length, I don't need to use an index to get the items out.

I feel like there's a way of doing this in C# using LINQ, but I can't figure out what it might be. Is there some easy method of iterating across multiple associated collections?

Edit:

This is a little better, I think - at least, in the case where I have the luxury of zipping the collections manually at declaration, and where all the collections contain objects of the same type:

List<string[]> items = new List<string[]>
{
    new [] {"DOC", "DocDate"},
    new [] {"CON", "ConUserDate"},
    new [] {"SCH", "SchDate"}
};
foreach (string[] item in items)
{
    Debug.Assert(item.Length == 2);
    string entType = item[0];
    string dateField = item[1];
    // do stuff with the associated entType and dateField
}
like image 383
Robert Rossney Avatar asked Mar 06 '09 01:03

Robert Rossney


2 Answers

In .NET 4.0 they're adding a "Zip" extension method to IEnumerable, so your code could look something like:

foreach (var item in entTypes.Zip(dateFields, 
    (entType, dateField) => new { entType, dateField }))
{
    // do stuff with item.entType and item.dateField
}

For now I think the easiest thing to do is leave it as a for loop. There are tricks whereby you can reference the "other" array (by using the overload of Select() that provides an index, for example) but none of them are as clean as a simple for iterator.

Here's a blog post about Zip as well as a way to implement it yourself. Should get you going in the meantime.

like image 54
Matt Hamilton Avatar answered Oct 02 '22 21:10

Matt Hamilton


Create a struct?

struct Item
{
    string entityType;
    string dateField;
}

Pretty much the same as your Pythonic solution, except type-safe.

like image 27
Smashery Avatar answered Oct 02 '22 21:10

Smashery