IEnumerator<T> / IEnumerable<T> with position stored only temporarily? - c#

I'm developing a graph where I need to keep the memory usage per node as low as possible. Each node implements IEnumerator / IEnumerable.
IEnumerator / IEnumerable make use of "position" in the canonical examples, which is a persistent cursor value required for iteration (e.g. as used by foreach).
What I need to avoid is storing this "position" value internally to the node itself, as this adds overhead where every byte counts.
How can I construct the node class such that a temporary object stores this value -- preferably on the stack -- only while an iteration is taking place, and not as part of the node itself? Is this possible?

Typically an IEnumerable<T> doesn't store a position - only an IEnumerator<T> does. (Iterator block implementations are odd in terms of implementing both, but they're definitely an anomaly.)
I suggest that you take the same approach that List<T> does: implement IEnumerable<T> with explicit interface implementation, but also have a public method returning a custom mutable struct (horrible I know, but it does solve your problem) which contains a reference to your node and the position within it. When you iterate using foreach, that struct value will only be stored on the stack (normally - assuming you're not doing this within an iterator block, for example).
The normal implementation would be to create a mutable reference type just for the IEnumerator<T>. Normally this is okay as even if you have a lot of IEnumerable<T> values live at the same time, you have few IEnumerator<T> values. Are you concerned about the concurrent number of live objects, or garbage collection?

If "node" is the underlying data, then it is very incorrect to store the position in the node, as you are meant to be able to have separate enumerators. It is unclear how you are currently implementing this API, but if you use an " iterator block " with the position as a local variable it will be done correctly, but on the heap. You can also implement an iterator manually on the stack by creating a struct iterator. It is important that the public GetEnumerator() is returned as the struct type, so you will need to use explicit interface implementation for IEnumerable etc. Note that foreach over Node directly will use the stack, but IEnumerable etc will use the heap.
For example (using a basic linked-list):
using System;
using System.Collections;
using System.Collections.Generic;
class Program
{
static void Main()
{
var list = new MyList<int>();
list.Add(1);
list.Add(2);
list.Add(3);
foreach (var i in list)
{ // this IS NOT using IEnumerable/IEnumerable<T>
Console.WriteLine(i);
}
}
}
public class MyList<T> : IEnumerable<T>
{
internal sealed class Node
{
private readonly T value;
public Node Next { get; set; }
public T Value { get { return value; } }
public Node(T value) { this.value = value; }
}
Node root;
public void Add(T value)
{
var newNode = new Node(value);
var node = root;
if (node == null) root = newNode;
else
{
while (node.Next != null) node = node.Next;
node.Next = newNode;
}
}
public Enumerator GetEnumerator() { return new Enumerator(this); }
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
IEnumerator<T> IEnumerable<T>.GetEnumerator() { return GetEnumerator(); }
public struct Enumerator : IEnumerator, IEnumerator<T>
{
void IDisposable.Dispose() { node = null; list = null; }
void IEnumerator.Reset() { node = null; }
object IEnumerator.Current { get { return Current; } }
private MyList<T> list;
private Node node;
public bool MoveNext()
{
if (node == null)
{
node = list.root;
return node != null;
}
else
{
if (node.Next == null) return false;
node = node.Next;
return node != null;
}
}
internal Enumerator(MyList<T> list) { this.list = list; node = null; }
public T Current { get { return node == null ? default(T) : node.Value; } }
}
}

Related

What does a HashSet Enumerator do?

I'm not used to write C# code, only Java and Python.
Now I found some code example for an algorithm which is only available in C#.
There is one structure I don't understand, it is the Enumerator.
HashSet<Node>.Enumerator enumerator = hashSet.GetEnumerator();
enumerator.MoveNext();
Item next = enumerator.Current;
So Item is the data type stored in the HashSet hashSet. Is this equal to a for-loop iterating over a HashSet or how else can that be translated into python or java?
GetEnumerator() methods are presented in some data structures in C# such as List, Set, etc. It enables doing iteration through. Actually, foreach internally makes use of it.
foreach statement is to iterate through the elements of certain data structures. A foreach can be used when all of the following conditions hold:
The data structure implements either IEnumerable(which is to
satisfy legacy codes before generics) or IEnumerable<T> for some
type T.
You do not need to know the locations in the data structure of the
individual elements.
For example, the string class implements both IEnumerable and IEnumerable<Char>.
The IEnumerable<T> interface implies the data structure requires two methods:
public IEnumerator<T> GetEnumerator()
IEnumerator IEnumerable.GetEnumerator()
The latter method is required only because IEnumerable<T> is a subtype of IEnumerable, and that interface requires a GetEnumerator method that returns a non-generic IEnumerator. Both of these methods should return the same object; hence, because IEnumerator<T> is also a subtype of IEnumerator, this method can simply call the first method:
System.Collections.IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
As you can see, the IEnumerable.GetEnumerator() method returns a reference to another interface named System.Collections.IEnumerator. This interface provides the infrastructure to allow the caller to traverse the internal objects contained by the IEnumerable-compatible container:
public interface IEnumerator
{
bool MoveNext (); // Advance the internal position of the cursor.
object Current { get;} // Get the current item (read-only property).
void Reset (); // Reset the cursor before the first member.
}
Let's exemplify it.
public class PowersOfThree : IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
return new PowersOfThreeEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
internal class PowersOfThreeEnumerator : IEnumerator<int>
{
private int index = 0;
public int Current
{
get { return (int)System.Math.Pow(3, index); }
}
object System.Collections.IEnumerator.Current
{
get { return Current; }
}
public bool MoveNext()
{
index++;
if (index > 10)
return false;
else
return true;
}
public void Reset()
{
index = 0;
}
public void Dispose()
{
}
}
public class Test
{
public static void Main(string[] str)
{
var p2 = new PowersOfThree();
foreach (int p in p2)
{
System.Console.WriteLine(p);
}
}
}
Current method returns the same element until MoveNext method is called. The initial index is 0 each MoveNext method increments the index from 1 to 10, inclusively, then it returns false. When the enumerator is at this position, subsequent calls to MoveNext also return false.
Do you see that what happened to Current when MoveNext returned false? Can you set Current to the first element of the collection again?
If you don't reinstantiate new enumerator, no.

how do I create GetEnumerator of my circular list?

I have to create my own circular list, I using the generic one.
first i create the Node<D> class which represents the data and the next of the element
private class Node<D> {
public D info;
public Node<D> next;
public Node() {
}
public Node(D p) {
info = p;
}
}
To create the circular list, I create the circularList<T> class. this class using Node<> as item of the element.
Here is the CircularList<T> class
class CircularList<T> : IEnumerable<T> {
public Node<T> start;
public Node<T> rear;
public int count = 0;
public CircularList(T firstItem) {
start = new Node<T>(firstItem);
rear = start;
rear.next = start;
}
public void Insert(T newItem) {
//Inserting code here
}
public void Update(T oldItem, T newItem) {
//Updating code is here
}
public void Delete(T theItem) {
//deleting code is here
}
}
when I start to loop using foreach
foreach(string item in CircularList<string>){
}
I got an error says that the circularlist class needs GetEnumerator().
Actually I can loop all of my circular list, but I am using do-while and I need Node<T> to start the loop. but I don't want using Node and do-while.
How do I create the GetEnumerator()?
Any help appreciated. :)
Thank you
Note: I really-really don't understand about IEnumerable and those things, please go easy with the example and explanation.
You need to implement GetEnumerator() method from IEnumerable for the foreach to work.
Use something like following:
public class CircularList<T> : IEnumerable<T>
{
private List<T> mylist = new List<T>();
public T this[int index]
{
get
{
return this.mylist[index];
}
set
{
this.mylist.Insert(index, value);
}
}
public IEnumerator<T> GetEnumerator()
{
return this.mylist.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
mylist maintains the list of type T which you would insert, update and delete.
EDIT
myList is just the backing storage of your "custom" list. As long as you are implementing your underlying functionality correctly, myList could be array, arraylist and so on.
For simplicity, I've used List<T> here which already implements the interface IEnumerable<T> and IEnumerator<T>( notice IEnumera**tor** not IEnumerable).
See this answer for more details on the difference between IEnumerator and IEnumerable
Moreover, The foreach statement hides the complexity of the enumerators.
See IEnumerator for more details.
The compiler turns the foreach into something like this:
CircularList<string> testList=new CircularList<string>();
IEnumerator testEnumerator= testList.GetEnumerator();
while (testEnumerator.MoveNext())
{
string yourForEachIteratorVariable = (string)testEnumerator.Current
...
}
Please note that the codes here are only for the illustration purposes. You could/should modify to make it more flexible and "performant" according to your need/requirement.
And for linked list, you don't need a backing List<T>, you could simply add/insert on your head node and implement GetEnumerator() something like below:
public IEnumerator<T> GetEnumerator()
{
var node = start;
while(node != null)
{
yield return node.info;
node = node.next;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

How can I implement IEnumerator<T>?

This code is not compiling, and it's throwing the following error:
The type 'TestesInterfaces.MyCollection' already contains a definition for 'Current'
But when I delete the ambiguous method, it keeps giving other errors.
Can anyone help?
public class MyCollection<T> : IEnumerator<T>
{
private T[] vector = new T[1000];
private int actualIndex;
public void Add(T elemento)
{
this.vector[vector.Length] = elemento;
}
public bool MoveNext()
{
actualIndex++;
return (vector.Length > actualIndex);
}
public void Reset()
{
actualIndex = -1;
}
void IDisposable.Dispose() { }
public Object Current
{
get
{
return Current;
}
}
public T Current
{
get
{
try
{
T element = vector[actualIndex];
return element;
}
catch (IndexOutOfRangeException e)
{
throw new InvalidOperationException(e.Message);
}
}
}
}
I think you're misunderstanding IEnumerator<T>. Typically, collections implement IEnumerable<T>, not IEnumerator<T>. You can think of them like this:
When a class implements IEnumerable<T>, it is stating "I am a collection of things that can be enumerated."
When a class implements IEnumerator<T>, it is stating "I am a thing that enumerates over something."
It is rare (and probably wrong) for a collection to implement IEnumerator<T>. By doing so, you're limiting your collection to a single enumeration. If you try to loop through the collection within a segment of code that's already looping through the collection, or if you try to loop through the collection on multiple threads simultaneously, you won't be able to do it because your collection is itself storing the state of the enumeration operation. Typically, collections (implementing IEnumerable<T>) return a separate object (implementing IEnumerator<T>) and that separate object is responsible for storing the state of the enumeration operation. Therefore, you can have any number of concurrent or nested enumerations because each enumeration operation is represented by a distinct object.
Also, in order for the foreach statement to work, the object after the in keyword, must implement IEnumerable or IEnumerable<T>. It will not work if the object only implements IEnumerator or IEnumerator<T>.
I believe this is the code you're looking for:
public class MyCollection<T> : IEnumerable<T>
{
private T[] vector = new T[1000];
private int count;
public void Add(T elemento)
{
this.vector[count++] = elemento;
}
public IEnumerator<T> GetEnumerator()
{
return vector.Take(count).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
You need to define the interface the current is implementing.
Object IEnumerator.Current
{
//
}
public T Current
{
//
}
This way your class has 2 Current properties. but you can access them both.
MyCollection<string> col = new MyCollection<string>();
var ienumeratort = col.Current; //Uses IEnumerator<T>
var ienumerator = (IEnumerator)col.Current; //uses IEnumerator
I think with C# 2.0 onwards, you have a very easy way of implementing iterator and compiler does a lot of heavy lifting behind the scene by creating state machine. It's worth looking into it. Having said that, in that case your implementation would look something below:
public class MyCollection<T>
{
private T[] vector = new T[1000];
private int actualIndex;
public void Add(T elemento)
{
this.vector[vector.Length] = elemento;
}
public IEnumerable<T> CreateEnumerable()
{
for (int index = 0; index < vector.Length; index++)
{
yield return vector[(index + actualIndex)];
}
}
}
I am not sure about the purpose of actualIndex though - but i hope you get the idea.
After proper initialization of MyCollection, below is snippet somewhat looks like from consumer perspective:
MyCollection<int> mycoll = new MyCollection<int>();
foreach (var num in mycoll.CreateEnumerable())
{
Console.WriteLine(num);
}

Call Compare Method from another class

Please help me to resolve the following problem:
First of all, I have one class
namespace ProbA
{
public class A : IComparer
{
Private int a;
public int IComparer.Compare(object CurrentNode, object DataNode)
{
WBPMember Current = (WBPMember)CurrentNode;
WBPMember Data = (WBPMember)DataNode;
return Current.a- Data.a;
}
}
}
namespace BST
{
public class BinarySearchTree<T> : ICollection<T>, IEnumerable<T>
{
public virtual void Add(T data)
{
// create a new Node instance
BinaryTreeNode<T> n = new BinaryTreeNode<T>(data);
int result;
BinaryTreeNode<T> current = root, parent = null;
while (current != null)
{
result = /**** I need to call the Class A compare method.
}
}
}
}
I want to execute ClassA Compare method, when following statement execute in ProbA assembly.
A objA = new A();
BinarySearchTree<A> bst = new BinarySearchTree<A>();
Bst.Add(objA);
Problem is both classes are in different libraries. And BinarySearchTree is generic class. So how can i compare A typed object in Add function of BinarySearchTree class.
I update this post for more clarification.
Let me describe my problem more clearly.
I have some type of businessrules. And as per different business rules , I need to construct different type of BST. Offcouse, BST generates at the same logic but on the different kind of logic of comparision.
Lets say, I have BusineesRules assembly. And it contains 4 kind of rules like Business1, Business2, Business3. Business4.
And I have an assembly for generating BST and other traversal methods. This BST is fully generic and in assembly BST
Now when I need to implement compare method in each class.
Like,.
Public Class Business1: IComparer
{
// Implemetation of Icompare.
}
Same for all the other classes.
When I try to add instance of Business1 in BST, make comparision based on its own implementation and same for other classes.
Code for BST is given below:
public class BinarySearchTree<T> : ICollection<T>, IEnumerable<T>
{
#region "Private Member Variables"
private BinaryTreeNode<T> root = null;
private int count = 0;
private IComparer<T> comparer = Comparer<T>.Default; // used to compare node values when percolating down the tree
#endregion
#region Constructors
public BinarySearchTree() { }
public BinarySearchTree(IComparer<T> comparer)
{
this.comparer = comparer;
}
#endregion
public virtual void Add(T data)
{
// create a new Node instance
BinaryTreeNode<T> n = new BinaryTreeNode<T>(data);
int result;
// now, insert n into the tree
// trace down the tree until we hit a NULL
BinaryTreeNode<T> current = root, parent = null;
while (current != null)
{
result = comparer.Compare(current.Value, data);
if (result == 0)
// they are equal - attempting to enter a duplicate - do nothing
return;
else if (result > 0)
{
// current.Value > data, must add n to current's left subtree
parent = current;
current = current.Left;
}
else if (result < 0)
{
// current.Value < data, must add n to current's right subtree
parent = current;
current = current.Right;
}
}
// We're ready to add the node!
count++;
if (parent == null)
// the tree was empty, make n the root
root = n;
else
{
result = comparer.Compare(parent.Value, data);
if (result > 0)
// parent.Value > data, therefore n must be added to the left subtree
parent.Left = n;
else
// parent.Value < data, therefore n must be added to the right subtree
parent.Right = n;
}
}
#endregion
** Add Generic comparer method.
This following class is added into businessrule classes assembly.
class BusinessRules: IComparer
{
public int Compare(object CurrentHNode, object DataNode)
{
TreeMember Current;
TreeMember Data;
if (CurrentHNode is Current)
{
Current = (TreeMember)CurrentHNode;
}
else
throw new ArgumentException("Object is not type of WBPMember");
if (DataNode is Data)
{
Data = (TreeMember)DataNode;
}
else
throw new ArgumentException("Object is not type of WBPMember");
return Current.TreeIndex - Data.TreeIndex;
}
}
You can see following line in the code.
“result = comparer.Compare(current.Value, data);”
But it is compare of binarysearch class. So I can call compare method business1 or business2.?
Is this comparor implemetation useful to compare objects in BinarySearchTree.Add() method?
One more important thing is that BST and other businessrule classes are different assemblies.
Well if you want to call Compare, your BinarySearchTree class will need to have a reference to an instance of the comparer. Assuming you want to make the binary search tree consistent, it seems logical to use the same comparer for all operations acting on a single instance of the search tree. I would suggest that:
You change your A class to implement IComparer<WBPMember> instead of just IComparer
You create a constructor in BinarySearchTree which takes an IComparer<T> and remembers it for later.
You optionally create a parameterless constructor in BinarySearchTree using the default comparer for T
Something like this:
public class BinarySearchTree<T> : ICollection<T>, IEnumerable<T>
{
private readonly IComparer<T> comparer;
public BinarySearchTree(IComparer<T> comparer)
{
// TODO: Work out how to handle comparer == null (could throw an
// exception, could use the default comparer).
this.comparer = comparer;
}
public BinarySearchTree() : this(Comparer<T>.Default)
{
}
// Now within Add, you can call comparer.Compare(current.Value, data)
}

How to use foreach keyword on custom Objects in C#

Can someone share a simple example of using the foreach keyword with custom objects?
Given the tags, I assume you mean in .NET - and I'll choose to talk about C#, as that's what I know about.
The foreach statement (usually) uses IEnumerable and IEnumerator or their generic cousins. A statement of the form:
foreach (Foo element in source)
{
// Body
}
where source implements IEnumerable<Foo> is roughly equivalent to:
using (IEnumerator<Foo> iterator = source.GetEnumerator())
{
Foo element;
while (iterator.MoveNext())
{
element = iterator.Current;
// Body
}
}
Note that the IEnumerator<Foo> is disposed at the end, however the statement exits. This is important for iterator blocks.
To implement IEnumerable<T> or IEnumerator<T> yourself, the easiest way is to use an iterator block. Rather than write all the details here, it's probably best to just refer you to chapter 6 of C# in Depth, which is a free download. The whole of chapter 6 is on iterators. I have another couple of articles on my C# in Depth site, too:
Iterators, iterator blocks and data pipelines
Iterator block implementation details
As a quick example though:
public IEnumerable<int> EvenNumbers0To10()
{
for (int i=0; i <= 10; i += 2)
{
yield return i;
}
}
// Later
foreach (int x in EvenNumbers0To10())
{
Console.WriteLine(x); // 0, 2, 4, 6, 8, 10
}
To implement IEnumerable<T> for a type, you can do something like:
public class Foo : IEnumerable<string>
{
public IEnumerator<string> GetEnumerator()
{
yield return "x";
yield return "y";
}
// Explicit interface implementation for nongeneric interface
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator(); // Just return the generic version
}
}
(I assume C# here)
If you have a list of custom objects you can just use the foreach in the same way as you do with any other object:
List<MyObject> myObjects = // something
foreach(MyObject myObject in myObjects)
{
// Do something nifty here
}
If you want to create your own container you can use the yield keyword (from .Net 2.0 and upwards I believe) together with the IEnumerable interface.
class MyContainer : IEnumerable<int>
{
private int max = 0;
public MyContainer(int max)
{
this.max = max;
}
public IEnumerator<int> GetEnumerator()
{
for(int i = 0; i < max; ++i)
yield return i;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
And then use it with foreach:
MyContainer myContainer = new MyContainer(10);
foreach(int i in myContainer)
Console.WriteLine(i);
From MSDN Reference:
The foreach statement is not limited to IEnumerable types and can be applied to an instance of any type that satisfies the following conditions:
has the public parameterless GetEnumerator method whose return type is either class, struct, or interface type,
the return type of the GetEnumerator method has the public Current property and the public parameterless MoveNext method whose return type is Boolean.
If you declare those methods, you can use foreach keyword without IEnumerable overhead. To verify this, take this code snipped and see that it produces no compile-time error:
class Item
{
public Item Current { get; set; }
public bool MoveNext()
{
return false;
}
}
class Foreachable
{
Item[] items;
int index;
public Item GetEnumerator()
{
return items[index];
}
}
Foreachable foreachable = new Foreachable();
foreach (Item item in foreachable)
{
}

Categories