Faster enumeration: using an array Enumeration

So I have a class with an array inside. My current strategy for listing class members is to use foreach (item x in classInstance.InsideArray) code foreach (item x in classInstance.InsideArray) . I would prefer to use foreach (item x in classInstance) and make the array private. My main concern is that I really need to avoid something slow; the array gets a lot of hits (and has a couple of hundred elements). It is very important that listing this array is cheap. One thought was to simply implement the IEnumerable<item> class, but InsideArray.getEnumerator() gives me a non-generic counter. I also tried to implement the IEnumerable interface. It worked, but it was very slow, possibly due to boxing.

Is there a way to make the class itself enumerable without increasing performance?

Normal code:

 //Class public class Foo { //Stuff public Item[,] InsideArray {get; private set;} } //Iteration. Shows up all over the place foreach (Item x in classInstance.InsideArray) { //doStuff } 

Corrected, much slower code:

 //Class public class Foo : IEnumerable { //Stuff private Item[,] InsideArray; System.Collections.IEnumerator System.Collections.IEnumerable GetEnumerator() { return InsideArray.GetEnumerator(); } } //Iteration. Shows up all over the place foreach (Item x in classInstance) { //doStuff } 

Note. Adding an implementation for a neon iterator is possible and faster than my slow solution, but it is still a little worse than just using the array directly. I was hoping there was a way to say C # somehow: "Hey, when I ask you to iterate over this object, iterate over its array as fast", but apparently this is not entirely possible ... at least from the suggested answers still.

+4
source share
4 answers

How to add an indexer to a class:

 public MyInsideArrayType this[int index] { get{return this.insideArray[index]; } 

And if you really need foreach features:

 public IEnumerable<MyInsideArrayType> GetEnumerator() { for(int i = 0; i<this.insideArray.Count;i++) { yield return this[i]; } } 
+1
source

A custom iterator can do this faster ( edited to return as a known type):

 Basic: 2468ms - -2049509440 Bespoke: 1087ms - -2049509440 

(you should use ArrayIterator directly as Foo GetEnumerator - essentially, by copying code from ArrayEnumerator.GetEnumerator, I want to show that a typed iterator is faster than an interface)

With code:

 using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; class Foo { public struct ArrayIterator<T> : IEnumerator<T> { private int x, y; private readonly int width, height; private T[,] data; public ArrayIterator(T[,] data) { this.data = data; this.width = data.GetLength(0); this.height = data.GetLength(1); x = y = 0; } public void Dispose() { data = null; } public bool MoveNext() { if (++x >= width) { x = 0; y++; } return y < height; } public void Reset() { x = y = 0; } public T Current { get { return data[x, y]; } } object IEnumerator.Current { get { return data[x, y]; } } } public sealed class ArrayEnumerator<T> : IEnumerable<T> { private readonly T[,] arr; public ArrayEnumerator(T[,] arr) { this.arr = arr; } public ArrayIterator<T> GetEnumerator() { return new ArrayIterator<T>(arr); } System.Collections.Generic.IEnumerator<T> System.Collections.Generic.IEnumerable<T>.GetEnumerator() { return GetEnumerator(); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } } public int[,] data; public IEnumerable<int> Basic() { foreach (int i in data) yield return i; } public ArrayEnumerator<int> Bespoke() { return new ArrayEnumerator<int>(data); } public Foo() { data = new int[500, 500]; for (int x = 0; x < 500; x++) for (int y = 0; y < 500; y++) { data[x, y] = x + y; } } static void Main() { Test(1); // for JIT Test(500); // for real Console.ReadKey(); // pause } static void Test(int count) { Foo foo = new Foo(); int chk; Stopwatch watch = Stopwatch.StartNew(); chk = 0; for (int i = 0; i < count; i++) { foreach (int j in foo.Basic()) { chk += j; } } watch.Stop(); Console.WriteLine("Basic: " + watch.ElapsedMilliseconds + "ms - " + chk); watch = Stopwatch.StartNew(); chk = 0; for (int i = 0; i < count; i++) { foreach (int j in foo.Bespoke()) { chk += j; } } watch.Stop(); Console.WriteLine("Bespoke: " + watch.ElapsedMilliseconds + "ms - " + chk); } } 
+5
source

Pass your IEnumerable<item> array before calling GetEnumerator() , and you get a generic IEnumerator . For instance:

 string[] names = { "Jon", "Marc" }; IEnumerator<string> enumerable = ((IEnumerable<string>)names).GetEnumerator(); 

It may still be a little slower than listing the array directly using foreach (which the C # compiler does differently), but at least you won't have anything in the way.

EDIT:

Well, you said that your other attempt used an indexer. You can try this approach, although I do not think it will be faster:

 public IEnumerable<Item> Items { get { foreach (Item x in items) { yield return x; } } } 

An alternative would be to try to avoid using a two-dimensional array for starters. Is this an absolute requirement? How often do you repeat a single array after creating it? It might be worth spending some time creating to make iteration cheaper.

EDIT: Another suggestion, which is slightly off the wall ... instead of passing the iterator back to the caller, why not make the caller say what to do with each element using a delegate?

 public void ForEachItem(Action action) { foreach (Item item in items) { action(item); } } 

Downsides:

  • You are responsible for calling a delegate with every access.
  • It is hard to break out of the loop (except throw an exception). There are different ways to approach this, but let me cross this bridge when we get to it.
  • Developers who are not familiar with delegates can get a little confused.
+3
source

All forms of iteration are cheap. If anyone at this daylight age somehow managed to write and publish an expensive iterator, they would (correctly) be burned at the stake.

Premature optimization is evil.

Greetings. Whale.

-5
source

All Articles