I'm trying to track down a bug in our code. I've boiled it down to the snippet below. In the example below I have a grid of ints (a list of rows), but I want to find the indexes of the columns that have a 1. The implementation of this is to create an enumerator for each row and step through each column in turn by keeping the enumerators in step.
class Program
{
static void Main(string[] args)
{
var ints = new List<List<int>> {
new List<int> {0, 0, 1}, // This row has a 1 at index 2
new List<int> {0, 1, 0}, // This row has a 1 at index 1
new List<int> {0, 0, 1} // This row also has a 1 at index 2
};
var result = IndexesWhereThereIsOneInTheColumn(ints);
Console.WriteLine(string.Join(", ", result)); // Expected: "1, 2"
Console.ReadKey();
}
private static IEnumerable<int> IndexesWhereThereIsOneInTheColumn(
IEnumerable<List<int>> myIntsGrid)
{
var enumerators = myIntsGrid.Select(c => c.GetEnumerator()).ToList();
short i = 0;
while (enumerators.All(e => e.MoveNext())) {
if (enumerators.Any(e => e.Current == 1))
yield return i;
i++;
if (i > 1000)
throw new Exception("You have gone too far!!!");
}
}
}
However I have noticed that MoveNext()
is not remembered each time around the while
loop. MoveNext()
always returns true, and Current
is always 0. Is this a purposeful feature of Linq to make it more side effect free?
I noticed that this works:
private static IEnumerable<int> IndexesWhereThereIsOneInTheColumn(
IEnumerable<List<int>> myIntsGrid)
{
var enumerators = myIntsGrid.Select(c =>
c.ToArray().GetEnumerator()).ToList(); // added ToArray()
short i = 0;
while (enumerators.All(e => e.MoveNext())) {
if (enumerators.Any(e => (int)e.Current == 1)) // added cast to int
yield return i;
i++;
}
}
So is this just a problem with List?
foreach
loops? – Littonforeach
. My first attempt had twobreak
s in it, and I think that the Linq implementation is cleaner. – Shoemaker