By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
454,424 Members | 1,402 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 454,424 IT Pros & Developers. It's quick & easy.

foreach with parallel iterations of multiple properties

P: n/a
Is it possible to write a foreach so that it simultaneously iterates through
two collections ( or two properties of the same collection ) ?

Following is *only meant as an example* :

-- iterate a dictionary obtaining the next key and value on each iteration.

The following doesn't work

foreach ( string key in MyDictionary.Keys , object value in
MyDictionary.Values )
{
.... but perhaps there's some other way ...


Jul 8 '08 #1
Share this Question
Share on Google+
6 Replies


P: n/a
John A Grandy wrote:
Is it possible to write a foreach so that it simultaneously iterates through
two collections ( or two properties of the same collection ) ?
No, because there's no meaningful definition of "simultaneous" (what should
happen if one of the iterations is done before the other one?)
Following is *only meant as an example* :

-- iterate a dictionary obtaining the next key and value on each iteration.

The following doesn't work

foreach ( string key in MyDictionary.Keys , object value in
MyDictionary.Values )
{
... but perhaps there's some other way ...
What type is "MyDictionary"? It should implement
IEnumerable<KeyValuePair<TKey, TValue>>, like IDictionary<TKey, TValue>
does. Then it's a matter of writing

foreach (KeyValuePair<string, objectp in MyDictionary) {
string key = p.Key;
object value = p.Value;
...
}

If it's one of the legacy collection types that has no intuitive IEnumerable
implementation, it's a simple matter of iterating over the keys only:

foreach (string key in MyDictionary.Keys) {
object value = MyDictionary[key];
...
}

Of course, since you specify that this is only "an example", you may not be
talking about dictionaries at all. It's always possible to use enumerators
directly for advanced scenarios:

using (IEnumerator<stringiKeys = MyDictionary.Keys.GetEnumerator()) {
using (IEnumerator<objectiObject = MyDictionary.Values.GetEnumerator()) {
// use .MoveNext() and .Current here as you please
}
}

But this is seldom necessary, and the resulting code isn't very readable.

--
J.
Jul 8 '08 #2

P: n/a
Re making it readable... perhaps an extension method (or take of the "this"
in C# 2 to get a static helper method) to walk the two in parallel;
something like below; this could be used i.e.

collectionA.ForEach(collectionB, (a,b)=Console.WriteLine("{0}/ {1}", a,b);

which isn't exactly unreadable...

Marc

public static void ForEach<TLhs, TRhs>(this IEnumerable<TLhs>
leftSequence,
IEnumerable<TRhsrightSequence, Action<TLhs, TRhsaction)
{
if (leftSequence == null) throw new
ArgumentNullException("leftSequence");
if (rightSequence == null) throw new
ArgumentNullException("rightSequence");
if (leftSequence == null) throw new ArgumentNullException("action");
using (var lhs = leftSequence.GetEnumerator())
using (var rhs = rightSequence.GetEnumerator())
{
while (lhs.MoveNext() && rhs.MoveNext())
{
action(lhs.Current, rhs.Current);
}
}
}
Jul 9 '08 #3

P: n/a
On Jul 8, 9:48*pm, Jeroen Mostert <jmost...@xs4all.nlwrote:
If it's one of the legacy collection types that has no intuitive IEnumerable
implementation, it's a simple matter of iterating over the keys only:

* *foreach (string key in MyDictionary.Keys) {
* * *object value = MyDictionary[key];
* * *...
* *}

Of course, since you specify that this is only "an example", you may not be
talking about dictionaries at all. It's always possible to use enumerators
directly for advanced scenarios:

* *using (IEnumerator<stringiKeys = MyDictionary.Keys.GetEnumerator()) {
* * *using (IEnumerator<objectiObject = MyDictionary.Values.GetEnumerator()) {
* * * *// use .MoveNext() and .Current here as you please
* * *}
* *}

But this is seldom necessary, and the resulting code isn't very readable.
This is debateful; personally, I would very much prefer the second
approach you propose to the first, if only because the first does an
unnecessary key lookup for every key, which can be pretty costly in a
loop. If using a legacy collection (I assume you mean Hashtable), then
the proper approach is to obtain an IDictionaryEnumerator from it
explicitly, and use that.
Jul 9 '08 #4

P: n/a
Pavel Minaev wrote:
On Jul 8, 9:48 pm, Jeroen Mostert <jmost...@xs4all.nlwrote:
>If it's one of the legacy collection types that has no intuitive IEnumerable
implementation, it's a simple matter of iterating over the keys only:

foreach (string key in MyDictionary.Keys) {
object value = MyDictionary[key];
...
}

Of course, since you specify that this is only "an example", you may not be
talking about dictionaries at all. It's always possible to use enumerators
directly for advanced scenarios:

using (IEnumerator<stringiKeys = MyDictionary.Keys.GetEnumerator()) {
using (IEnumerator<objectiObject = MyDictionary.Values.GetEnumerator()) {
// use .MoveNext() and .Current here as you please
}
}

But this is seldom necessary, and the resulting code isn't very readable.

This is debateful; personally, I would very much prefer the second
approach you propose to the first, if only because the first does an
unnecessary key lookup for every key, which can be pretty costly in a
loop.
Meh. If it's a dictionary type, the lookup time shouldn't matter except in
pathological cases. Getting an explicit enumerator for the values isn't
necessarily faster (I'll grant you that it probably isn't any *slower*,
though, since the implementation could always use the key-lookup method if
it couldn't think of anything better).
If using a legacy collection (I assume you mean Hashtable),
That's one of them. There are more custom collections in the framework than
you can shake a stick at, actually, some of which don't even implement
IEnumerable (but let's politely ignore those).
then the proper approach is to obtain an IDictionaryEnumerator from it
explicitly, and use that.
This works for Hashtable; it doesn't work for (say) NameObjectCollectionBase
and derivates, which return an enumerator over the keys only. If you *can*
obtain an enumerator that obtains the values as pairs, then yes, by all
means use that in preference to any of these approaches.

--
J.
Jul 9 '08 #5

P: n/a
On Jul 9, 8:19*am, "Marc Gravell" <marc.grav...@gmail.comwrote:
Re making it readable... perhaps an extension method (or take of the "this"
in C# 2 to get a static helper method) to walk the two in parallel;
something like below; this could be used i.e.
<snip>

FWIW, Eric Lippert mentioned that MS effectively "missed" an operator
for LINQ here - the "Zip" operator. who knows, it may even get
implemented in a future version.

Of course, there are options here in terms of what should happen when
the left or right sequence ends before the other one does - it could
through an exception, return pairs with the default value for the
type, or just end abruptly (as yours does).

Candidate for MiscUtil, perhaps?

Jon
Jul 9 '08 #6

P: n/a
On Jul 9, 6:52*pm, "Jon Skeet [C# MVP]" <sk...@pobox.comwrote:
On Jul 9, 8:19*am, "Marc Gravell" <marc.grav...@gmail.comwrote:
Re making it readable... perhaps an extension method (or take of the "this"
in C# 2 to get a static helper method) to walk the two in parallel;
something like below; this could be used i.e.

<snip>

FWIW, Eric Lippert mentioned that MS effectively "missed" an operator
for LINQ here - the "Zip" operator. who knows, it may even get
implemented in a future version.
For a laugh, here's a LINQ 1-liner that seems to do that:

xs.Select((x, i) =new { x = x, i = i }).Join(ys.Select((y, i) =new
{ y = y, i = i }), xi =xi.i, yi =yi.i, (xi, yi) =new { xi.x,
yi.y })

Performance-wise, of course, this is so bad it's not even a contender.
Jul 10 '08 #7

This discussion thread is closed

Replies have been disabled for this discussion.