Can you run a foreach in reverse order?

F

Fabio Cannizzo

Is it possible to do something similar to the STL iterators, i.e. to execute
a foreach loop in reverse order?

Thanks,
Fabio
 
R

Randy A. Ynchausti

Fabio,
Is it possible to do something similar to the STL iterators, i.e. to
execute a foreach loop in reverse order?

One could simply reverse the order of the collection before executing the
foreach loop. I know that is a second-best options. However, it will work.

Regards,

Randy
 
J

Jon Skeet [C# MVP]

Fabio Cannizzo said:
Is it possible to do something similar to the STL iterators, i.e. to execute
a foreach loop in reverse order?

No - and not every iterator would be able to support that behaviour
anyway. Consider a foreach which was based off a stream coming in from
a network - you'd have to wait to find the end of the stream (if that
ever happened) before you could start giving back numbers.

Another example - consider an iterator which yielded prime numbers, in
order. What would a reversed iterator do?
 
P

Peter Kirk

Another example - consider an iterator which yielded prime numbers, in
order. What would a reversed iterator do?

Easy - start from the highest prime number, and work downwards. Was it a
trick question?
 
J

Jon Skeet [C# MVP]

Peter said:
Easy - start from the highest prime number, and work downwards. Was it a
trick question?

I'm not sure whether you're being sarcastic or not - apologies if you
were joking, just ignore the rest of this post. There *is* no "highest
prime number". Prime numbers have been proved (IIRC) to stretch to
infinity. The iterator would never finish, so there's no end.

Here's a simpler one - an iterator which gives 1, 2, 3, 4 etc using
some "arbitrary length" datatype (like Java's BigInteger). What's the
biggest natural number?

Jon
 
N

Nick Hounsome

Jon Skeet said:
No - and not every iterator would be able to support that behaviour
anyway. Consider a foreach which was based off a stream coming in from
a network - you'd have to wait to find the end of the stream (if that
ever happened) before you could start giving back numbers.

You are right but that is true whether you are programming C# or C++.

In STL an iterator is a pattern not a class. However in practice all reverse
iterators are std::reverse_iterator because this implements reverse
iteration by decorating either a bidirectional or random access iterator
(which is another pattern).

The closest you can get in .NET is a generic wrapper implementing
IEnumerable<T> and taking IList<T> in the constructor (IList<T> would
then be equivalent to a random access iterator in STL)

In practice almost all iterators in C++ that are reversible are random
access rather than merely bidirectional which means that they have array
like properties which means that they would almost certainly implement
IList<T> in C#
 
P

Peter Kirk

Jon Skeet said:
I'm not sure whether you're being sarcastic or not - apologies if you
were joking,

Ah, sorry, yes it was supposed to be humour.... never did quite get the hang
of that....
 
C

chris martin

Fabio Cannizzo said:
No - and not every iterator would be able to support that behaviour
anyway. Consider a foreach which was based off a stream coming in from
a network - you'd have to wait to find the end of the stream (if that
ever happened) before you could start giving back numbers.

Another example - consider an iterator which yielded prime numbers, in
order. What would a reversed iterator do?

I'm assuming you are talking about something other than executing a foreach
in reverse.

Why wouldn't this work if that's not the case.

[STAThread]
private static void Main()
{
foreach(int i in new ReverseEnumerator(new int[] {1, 2, 3, 4, 5, 6, 7, 8,
9, 10}))
{
Console.Write(i + " ");
}

Console.ReadLine();
}

public class ReverseEnumerator : IEnumerator, IEnumerable
{
private IList enumerable;
private int current = -1;

public ReverseEnumerator(IList enumerable)
{
this.enumerable = enumerable;
current = enumerable.Count;
}

public bool MoveNext()
{
current--;

bool toReturn = enumerable.Count > current && current < enumerable.Count
&& current > -1;

return toReturn;
}

public void Reset()
{
current = enumerable.Count;
}

public object Current
{
get { return enumerable[current]; }
}

public IEnumerator GetEnumerator()
{
return this;
}
}

chris marti
 
F

Fabio Cannizzo

Hi John.

I think Peter has a point. In the computer world the concept of infinite
does not exist.
Be it a set, an array or a collection, at any particular point in time it
will have a finite number of elements.

I understand that in C# these do not exists, but I do not agree they do not
make sense. The STL succesfully and conveninetly implement them.

Regards,
Fabio
 
J

Jon Skeet [C# MVP]

chris martin said:
I'm assuming you are talking about something other than executing a foreach
in reverse.

Why wouldn't this work if that's not the case.

Because your code requires that what you want to enumerate implements
IList. Not everything which implements IEnumerator or IEnumerable
implements IList.

<snip>
 
J

Jon Skeet [C# MVP]

Fabio Cannizzo said:
I think Peter has a point. In the computer world the concept of infinite
does not exist.

It does in my view. When does a random number generator stop? Similarly
a Stream never has to end, but could be iterated over.
Be it a set, an array or a collection, at any particular point in time it
will have a finite number of elements.

However, iterators aren't always over arrays or collections.
I understand that in C# these do not exists, but I do not agree they do not
make sense. The STL succesfully and conveninetly implement them.

So what would it do with the following iterator?

using System;
using System.Collections;
using System.Collections.Generic;

public class RandomIterator : IEnumerable<int>
{
Random rng;

public RandomIterator (int seed)
{
rng = new Random(seed);
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

public IEnumerator<int> GetEnumerator()
{
while (true)
{
yield return rng.Next(0, int.MaxValue);
}
}
}
 
C

chris martin

chris martin said:
Because your code requires that what you want to enumerate implements
IList. Not everything which implements IEnumerator or IEnumerable
implements IList.

<snip>

Certainly that was a oversight on my part.
 
W

William Stacey [MVP]

You could create a custom enumerator and foreach over that.

--
William Stacey [MVP]

| Is it possible to do something similar to the STL iterators, i.e. to
execute
| a foreach loop in reverse order?
|
| Thanks,
| Fabio
|
|
 
N

Nick Hounsome

Jon Skeet said:
Because your code requires that what you want to enumerate implements
IList. Not everything which implements IEnumerator or IEnumerable
implements IList.

It is totally possible to write a wrapper that can take IList,IList<T> or
anything (by reflection) that includes appropriate methods/properties (these
would be this[] and Count). You could even allow things having Count and
implementing IEnumerable although it wouldn't be efficient.
 
J

Jon Skeet [C# MVP]

Nick said:
Because your code requires that what you want to enumerate implements
IList. Not everything which implements IEnumerator or IEnumerable
implements IList.

It is totally possible to write a wrapper that can take IList,IList<T> or
anything (by reflection) that includes appropriate methods/properties (these
would be this[] and Count).

Absolutely - and Chris's code does indeed cope with IList and would be
easy to change to do IList said:
You could even allow things having Count and
implementing IEnumerable although it wouldn't be efficient.

You could certainly do a "buffering" version that went to the end of
the IEnumerable *if* it terminated. It still wouldn't be as flexible as
foreach though, and that's my point - foreach doesn't make any
assumptions about the nature of the iterator, whereas the concept of a
reversible foreach *has* to assume that the iterator has an end.

Jon
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top