foreach with parallel iterations of multiple properties

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • John A Grandy

    foreach with parallel iterations of multiple properties

    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.Ke ys , object value in
    MyDictionary.Va lues )
    {


    .... but perhaps there's some other way ...




  • Jeroen Mostert

    #2
    Re: foreach with parallel iterations of multiple properties

    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 "simultaneo us" (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.Ke ys , object value in
    MyDictionary.Va lues )
    {
    >
    >
    ... but perhaps there's some other way ...
    >
    What type is "MyDictiona ry"? It should implement
    IEnumerable<Key ValuePair<TKey, TValue>>, like IDictionary<TKe y, TValue>
    does. Then it's a matter of writing

    foreach (KeyValuePair<s tring, 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.Ke ys) {
    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<st ringiKeys = MyDictionary.Ke ys.GetEnumerato r()) {
    using (IEnumerator<ob jectiObject = MyDictionary.Va lues.GetEnumera tor()) {
    // use .MoveNext() and .Current here as you please
    }
    }

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

    --
    J.

    Comment

    • Marc Gravell

      #3
      Re: foreach with parallel iterations of multiple properties

      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.For Each(collection B, (a,b)=Console.W riteLine("{0}/ {1}", a,b);

      which isn't exactly unreadable...

      Marc

      public static void ForEach<TLhs, TRhs>(this IEnumerable<TLh s>
      leftSequence,
      IEnumerable<TRh srightSequence, Action<TLhs, TRhsaction)
      {
      if (leftSequence == null) throw new
      ArgumentNullExc eption("leftSeq uence");
      if (rightSequence == null) throw new
      ArgumentNullExc eption("rightSe quence");
      if (leftSequence == null) throw new ArgumentNullExc eption("action" );
      using (var lhs = leftSequence.Ge tEnumerator())
      using (var rhs = rightSequence.G etEnumerator())
      {
      while (lhs.MoveNext() && rhs.MoveNext())
      {
      action(lhs.Curr ent, rhs.Current);
      }
      }
      }


      Comment

      • Pavel Minaev

        #4
        Re: foreach with parallel iterations of multiple properties

        On Jul 8, 9:48 pm, Jeroen Mostert <jmost...@xs4al l.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.Ke ys) {
             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<st ringiKeys = MyDictionary.Ke ys.GetEnumerato r()) {
             using (IEnumerator<ob jectiObject = MyDictionary.Va lues.GetEnumera tor()) {
               // 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 IDictionaryEnum erator from it
        explicitly, and use that.

        Comment

        • Jeroen Mostert

          #5
          Re: foreach with parallel iterations of multiple properties

          Pavel Minaev wrote:
          On Jul 8, 9:48 pm, Jeroen Mostert <jmost...@xs4al l.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.Ke ys) {
          > 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<st ringiKeys = MyDictionary.Ke ys.GetEnumerato r()) {
          > using (IEnumerator<ob jectiObject = MyDictionary.Va lues.GetEnumera tor()) {
          > // 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 IDictionaryEnum erator from it
          explicitly, and use that.
          This works for Hashtable; it doesn't work for (say) NameObjectColle ctionBase
          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.

          Comment

          • Jon Skeet [C# MVP]

            #6
            Re: foreach with parallel iterations of multiple properties

            On Jul 9, 8:19 am, "Marc Gravell" <marc.grav...@g mail.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

            Comment

            • Pavel Minaev

              #7
              Re: foreach with parallel iterations of multiple properties

              On Jul 9, 6:52 pm, "Jon Skeet [C# MVP]" <sk...@pobox.co mwrote:
              On Jul 9, 8:19 am, "Marc Gravell" <marc.grav...@g mail.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.Sele ct((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.

              Comment

              Working...