Home

Iterating Through a Collection

 

Enumerating the Members of a Collection

 

Introduction to System Collections

When studying arrays, we saw that you could use a for loop to visit each member of an array. This was also done with the help of the [] operator. In previous lessons, we saw that, when creating a collection, you should provide a method that allows you to retrieve a member of the collection. In both cases, you can list the members of an array or a collection through a technique called an enumeration.

Enumerating a collection consists of visiting each member of the list, for any reason judged necessary. For example, you can enumerate a collection to display a list of its members. You can enumerate a collection when looking for a member that responds to a certain criterion.

Besides, or instead of, a for loop, the .NET Framework provides another and better support for enumeration. In the C# language, you can enumerate a collection using the foreach operator, but the collection must be prepared for it: you cannot just use foreach for any collection. This support is provided through two main interfaces: IEnumerator and IEnumerable. These two interfaces are defined in the System.Collection namespace. Therefore, if you intend to use them, you can include this namespace in your source file.

Practical LearningPractical Learning: Introducing Built-In Collections

  1. Start Microsoft Visual C# and create a new Console Application named FlowerShop5
  2. To create a new file, on the main menu, click Project -> Add New Item...
  3. In the Templates list, click Code File
  4. Set the Name to FlowerAccessories and click Add
  5. In the empty file, type the following:
     
    public enum FlowerType
    {
         Roses      = 1,    // Why
         Lilies     = 102,  // these
         Daisies    = 104,  // fancy
         Carnations = 112,  // numbers?
         LivePlant  = 220,  // Just
         Orchids    = 234,  // for
         Tulips     = 242,  // the
         Iris       = 250,  // fun
         Mixed      = 462,  // of
         Other      = 464   // it
    }
    
    public enum FlowerColor
    {
        Red = 1,
        White,
        Yellow,
        Pink,
        Orange,
        Blue,
        Lavender,
        Mixed
    }
    
    public enum FlowerArrangement
    {
        Bouquet = 1,
        Balloon,
        Vase,
        Basket,
        Bundle,
        Any
    }
  6. To create a new class, in the Solution Explorer, right-click FlowerShop5 -> Add -> Class...
  7. Set the Name to Flower and press Enter
  8. Change the file as follows:
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace FlowerShop5
    {
        public class Flower
        {
            private decimal pc;
            public Flower Next;
            public FlowerType Type;
            public FlowerColor Color;
            public FlowerArrangement Arrangement;
    
            public Flower()
            {
                Type = FlowerType.Mixed;
                Color = FlowerColor.Mixed;
                Arrangement = FlowerArrangement.Vase;
                pc = 0.00M;
            }
    
            public Flower(FlowerType type, FlowerColor color,
                    FlowerArrangement argn, decimal price)
            {
                Type = type;
                Color = color;
                Arrangement = argn;
                pc = price;
            }
    
            public decimal UnitPrice
            {
                get { return pc; }
                set { pc = value; }
            }
        }
    }
  9. To create a new class, in the Class View, right-click FlowerShop5 -> Add -> Class...
  10. Set the Name to FlowerInventory and click Add
  11. Change the class as follows:
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace FlowerShop5
    {
        public abstract class AFlower
        {
            protected int items;
    
            public AFlower()
            {
                items = 0;
            }
    
            public int Count
            {
                get { return items; }
            }
    
            public abstract int Add(Flower obj);
            public abstract Flower Get(int index);
            public abstract bool Delete();
        }
    
        public class FlowerInventory : AFlower
        {
            public Flower Head;
            public Flower Inventory;
    
            public FlowerInventory()
            {
                Head = null;
            }
    
            public override int Add(Flower NewFlower)
            {
                Flower Sample = NewFlower;
    
                Sample.Next = Head;
                Head = Sample;
                return items++;
            }
    
            public override Flower Get(int index)
            {
                Flower Current = Head;
    
                for(int i = Count - 1;
                    i > index && Current != null;
                    i--)
                    Current = Current.Next;
                return Current;
            }
    
            public override bool Delete()
            {
                if (Head == null)
                {
                    Console.WriteLine("The inventory is empty");
                    return false;
                }
    
                Flower Current;
    
                Current = Head.Next;
                Head.Next = Current.Next;
                items--;
                return true;
            }
        }
    }
  12. Save all  

Introduction to the IEnumerator Interface

The IEnumerator interface provides the means of identifying the class that holds a sample of the items that will be enumerated. This interface is equipped with one property and two methods. To use the functionalities provided by the IEnumerator interface, you must create a class that implements it. You can start the class as follows:

public class Enumerator : IEnumerator
{
}

If your collection is an array-based list, you can start by declaring the base array in the class: Here is an example:

public class Enumerator : IEnumerator
{
    private double[] numbers;
}

If the collection is not array-based, you can declare a variable for the class that would be enumerated.

The role of the enumerator is to act on a collection. For this reason, the class should be prepared to receive an external collection. This can be done by passing it to a constructor of the enumerator. Here is an example:

public class Enumerator : IEnumerator
{
    private double[] numbers;

    public Enumerator(double[] list)
    {
    }
}

The internal collection would be used in the enumerator class. The external collection would be the source of the values of the list that would be enumerated. For these reasons, you can/should initialize the internal collection with the values of the external list. This can be done as follows:

public class Enumerator : IEnumerator
{
    private double[] numbers;

    public Enumerator(double[] list)
    {
        this.numbers = list;
    }
}

Practical Learning Practical Learning: Introducing Enumerations

  1. To create a new class, in the Class View, right-click FlowerShop5 -> Add -> Class...
  2. Set the Name of the class to FlowerIdentifier and click Add
  3. Change the file as follows:
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Collections;
    
    namespace FlowerShop5
    {
        public class FlowerIdentifier : IEnumerator
        {
            public FlowerInventory counts;
    
            public void Identify(FlowerInventory list)
            {
                this.counts = list;
            }
        }
    }
  4. Save the file

The Current Item of an Enumeration

In the previous lesson, when introducing some techniques of creating a list, we saw that you should have a type of tag, as a field, that allows you to monitor the item that is being currently accessed or used in the list. This is particularly valuable when visiting the members of the collection. The IEnumerator interface provides a property that is used to identify the current member of the list. This property is called Current. Because the current item is meant to be viewed only, the Current property is a read-only member. Based on the rules of abstract classes, remember that you must implement all members of an interface in the class that is based on it.

To implement the Current property, you can define its get accessor to return the item at the current position. This can be done as follows:

public class Enumerator : IEnumerator
{
    private double[] numbers;
    private int cur;

    public Enumerator(double[] list)
    {
        this.numbers = list;
    }

    public object Current
    {
        get { return numbers[cur]; }
    }
}

Practical Learning Practical Learning: Getting to the Current Item

  1. In the FlowerIdentifier.cs file, implement the IEnumerator.Current property as follows:
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Collections;
    
    namespace FlowerShop5
    {
        public class FlowerIdentifier : IEnumerator
        {
            private int curPosition = -1;
            public FlowerInventory counts;
    
            public void Identify(FlowerInventory list)
            {
                this.counts = list;
            }
    
            public object Current
            {
                get
                {
                    return this.counts.Get(this.curPosition);
                }
            }
        }
    }
  2. Save the file

Resetting the Tag of the Current Item

Although you should be able to identify the current item at any time, when the application starts, before the collection can be enumerated, the tag that is used to monitor the current item should be set to a value before the beginning of the count. This can be done by setting the tag to -1. Here is an example:

public class Enumerator : IEnumerator
{
    private double[] numbers;
    private int cur;

    public Enumerator(double[] list)
    {
        this.numbers = list;
        cur = -1;
    }

    public Object Current
    {
        get { return numbers[cur]; }
    }
}

While the collection is being used, at one moment you may want to reset the tag of the current item to its original position. To support this operation, the IEnumerator interface is equipped with a method named Reset. Its syntax is:

void Reset();

When implementing this method, simply assign a non-existing value, which is usually -1, to the monitoring tag of the current item. This can be done as follows:

public class Enumerator : IEnumerator
{
    private double[] numbers;
    private int cur;

    public Enumerator(double[] list)
    {
        this.numbers = list;
        cur = -1;
    }

    public object Current
    {
        get { return numbers[cur]; }
    }

    public void Reset()
    {
        cur = -1;
    }
}

When using the implementer of the IEnumerator interface, if you try accessing an item beyond the maximum number of items, the compiler would throw an IndexOutOfRangeException exception. For this reason, when anticipating a bad behavior, you should catch this exception when implementing the Current property.

Practical Learning Practical Learning: Resetting the Tag of the Current Item

  1. In the FlowerIdentifier.cs file, implement the IEnumerator.Reset() method as follows:
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Collections;
    
    namespace FlowerShop5
    {
        public class FlowerIdentifier : IEnumerator
        {
            private int curPosition = -1;
            public FlowerInventory counts;
    
            public void Identify(FlowerInventory list)
            {
                this.counts = list;
            }
    
            public Object Current
            {
                get
                {
                    try
                    {
                        return this.counts.Get(this.curPosition);
                    }
                    catch (IndexOutOfRangeException)
                    {
                        Console.WriteLine("The current item must be accessed " +
                                          "within the range of available items");
                    }
                }
            }
    
            public void Reset()
            {
                this.curPosition = -1;
            }
        }
    }
  2. Save the file

Moving to the Next Item in the Enumerator

In the previous lesson, we saw that, when using the items of a collection, one way you could locate one item from another was to be able to jump from one item to the next. This operation is also very important when enumerating a collection. To support this operation, the IEnumerator interface is quipped with the MoveNext() method. Its syntax is:

bool MoveNext();

When implementing this method, first increment the tag that monitors the current item of the collection. After incrementing the tag, check whether it is lower than the total number of items. If it is, return true. Otherwise, return false. This can be done as follows:

public class Enumerator : IEnumerator
{
    private double[] numbers;
    private int cur;

    public Enumerator(double[] list)
    {
        this.numbers = list;
        cur = -1;
    }

    public Object Current
    {
        get { return numbers[cur]; }
    }

    public void Reset()
    {
        cur = -1;
    }

    public bool MoveNext()
    {
        cur++;
        if (cur < numbers.Length)
            return true;
        else
            return false;
    }
}

Practical Learning Practical Learning: Moving to the Next Item in the Enumerator

  1. Implement the IEnumerator.MoveNext() method as follows:
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Collections;
    
    namespace FlowerShop5
    {
        public class FlowerIdentifier : IEnumerator
        {
            private int curPosition = -1;
            public FlowerInventory counts;
    
            public void Identify(FlowerInventory list)
            {
                this.counts = list;
            }
    
            public Object Current
            {
                get
                {
                    try
                    {
                        return this.counts.Get(this.curPosition);
                    }
                    catch (IndexOutOfRangeException)
                    {
                        Console.WriteLine("The current item must be accessed " +
                                          "within the range of available items");
                    }
    
    		return null;
                }
            }
    
            public void Reset()
            {
                this.curPosition = -1;
            }
    
            public bool MoveNext()
            {
                this.curPosition++;
    
                if (this.curPosition < counts.Count)
                    return true;
                else
                    return false;
            }
        }
    }
  2. Save the file
  1.  

An Enumerable Collection

 

Introduction

The IEnumerator interface is used to set up a collection for enumeration. The IEnumerator does not provide the functionality necessary to use foreach. The next step is to implement another interface called IEnumerable.

While the IEnumerator interface is used to identify the class that holds each value that will be visited, the IEnumerable interface is used to communicate with the collection whose items will be enumerated. For this reason, when implementing this class, you should provide the means of accessing the external collection. This can be done by passing a collection of the class that holds the values, to a constructor of the IEnumerable implementer.

Getting the Enumerator

To implement the IEnumerable interface, start by deriving a class from it. While the class implemented by the IEnumerator interface represents an object, the class that implements the IEnumerable interface is a collection. Here is an example:

public class Enumerable : IEnumerable
{
}

The new class does not know what collection it will be asked to enumerate. For this reason, in the new class, you should declare a member variable of the class that holds the values that will be enumerated. If the collection is array-based, you can create the field as follows:

public class Enumerable : IEnumerable
{
    private double[] numbers;
}

Eventually, when instantiating the IEnumerable implementer, you will need to pass it a collection of values. To make this possible, you can create a method in the new class and pass that collection of objects. Here is an example:

public class Enumerable : IEnumerable
{
    private double[] numbers;

    public void Identify(double[] values)
    {
    }
}

In this method, you can assign the member variable to the argument. You should also assign each member of the argument to its equivalent of the member of the argument. This can be done with a for loop as follows:

public class Enumerable : IEnumerable
{
    private double[] numbers;

    public void Identify(double[] values)
    {
        numbers = values;
        for (int i = 0; i < values.Length; i++)
            numbers[i] = values[i];
    }
}

To support the use of the foreach loop, the IEnumerable interface is equipped with (only) a method named GetEnumerator that you must implement. The IEnumerable.GetEnumerator() method returns an IEnumerator object. When implementing this method, you can return an object of the class that implements the IEnumerator interface, passing it the collection that was declared in the IEnumerable implementer. This can be done as follows: 

public class Enumerable : IEnumerable
{
    private double[] numbers;

    public void Identify(double[] values)
    {
        numbers = values;
        for (int i = 0; i < values.Length; i++)
            numbers[i] = values[i];
    }

    public IEnumerator GetEnumerator()
    {
        return new Enumerator(numbers);
    }
}

Practical Learning Practical Learning: Getting the Enumerator

  1. To create a new class, in the Class View, right-click FlowerShop5 -> Add -> Class...
  2. Set the Name of the class to Flowers and click Add
  3. Change the file as follows:
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Collections;
    
    namespace FlowerShop5
    {
        public class Flowers : IEnumerable
        {
            private FlowerInventory items;
    
            public void Locate(FlowerInventory list)
            {
                items = new FlowerInventory();
    
                for (int i = 0; i < list.Count; i++)
                    this.items.Add(list.Get(i));
            }
    
            public IEnumerator GetEnumerator()
            {
                FlowerIdentifier fid = new FlowerIdentifier();
    
                fid.Identify(items);
                return fid; 
            }
        }
    }
  4. Save the file

Using foreach

After implementing the IEnumerator and the IEnumerable interfaces, you can then use the foreach loop. To start, you must prepare the collection and its items for processing. Here is an example:

public class Exercise
{
    static int Main(string[] args)
    {
        double[] numbers = new double[5];
        numbers[0] = 224.52;
        numbers[1] = 60.48;
        numbers[2] = 1250.64;
        numbers[3] = 8.86;
        numbers[4] = 1005.36;

        return 0;
    }
}

To enumerate the collection, declare a variable based on the implementer of the IEnumerable and pass the collection to its constructor. Once this is done, you can then use the foreach. Here is an example:

using System;
using System.Collections;

public class Enumerator : IEnumerator
{
    private double[] numbers;
    private int cur;

    public Enumerator(double[] list)
    {
        this.numbers = list;
        cur = -1;
    }

    public Object Current
    {
        get { return numbers[cur]; }
    }

    public void Reset()
    {
        cur = -1;
    }

    public bool MoveNext()
    {
        cur++;
        if (cur < numbers.Length)
            return true;
        else
            return false;
    }
}

public class Enumerable : IEnumerable
{
    private double[] numbers;

    public void Identify(double[] values)
    {
        numbers = values;
        for (int i = 0; i < values.Length; i++)
            numbers[i] = values[i];
    }

    public IEnumerator GetEnumerator()
    {
        return new Enumerator(numbers);
    }
}

public class Exercise
{
    static int Main(string[] args)
    {
        double[] numbers = new double[5];
        numbers[0] = 224.52;
        numbers[1] = 60.48;
        numbers[2] = 1250.64;
        numbers[3] = 8.86;
        numbers[4] = 1005.36;

        Enumerable coll = new Enumerable();
        
        coll.Identify(numbers);
        foreach (double d in coll)
            Console.WriteLine("Item {0}", d); ;

        return 0;
    }
}

Practical Learning Practical Learning: Using foreach on an Enumerator

  1. Access the Program.cs file and change it as follows:
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace FlowerShop5
    {
        public class Program
        {
            static void Main(string[] args)
            {
                FlowerInventory fls = new FlowerInventory();
                Flower nice;
    
                nice = new Flower();
                nice.Type = FlowerType.Lilies;
                nice.Color = FlowerColor.White;
                nice.Arrangement = FlowerArrangement.Bouquet;
                nice.UnitPrice = 39.95M;
                fls.Add(nice);
    
                nice = new Flower();
                nice.Type = FlowerType.Daisies;
                nice.Color = FlowerColor.Mixed;
                nice.Arrangement = FlowerArrangement.Bouquet;
                nice.UnitPrice = 40.50M;
                fls.Add(nice);
    
                nice = new Flower();
                nice.Type = FlowerType.Carnations;
                nice.Color = FlowerColor.Lavender;
                nice.Arrangement = FlowerArrangement.Any;
                nice.UnitPrice = 34.85M;
                fls.Add(nice);
    
                nice = new Flower();
                nice.Type = FlowerType.Roses;
                nice.Color = FlowerColor.Pink;
                nice.Arrangement = FlowerArrangement.Bouquet;
                nice.UnitPrice = 29.95M;
                fls.Add(nice);
    
                nice = new Flower();
                nice.Type = FlowerType.Daisies;
                nice.Color = FlowerColor.Yellow;
                nice.Arrangement = FlowerArrangement.Vase;
                nice.UnitPrice = 29.95M;
                fls.Add(nice);
    
                Flowers collection = new Flowers();
                collection.Locate(fls);
    
              Console.WriteLine("//=//=//=//=//=//=//=//=//=//=//=//=//=//=//");
              Console.WriteLine("Total: {0} flower items in current inventory",
                    	    fls.Count);
              Console.WriteLine("--------------------------------------------");
                Console.WriteLine("Inventory Summary");
                foreach (Flower flr in collection)
                {
                    Console.WriteLine("------------------------");
                    Console.WriteLine("Flower Information");
                    Console.WriteLine("Type:        {0}", flr.Type);
                    Console.WriteLine("Color:       {0}", flr.Color);
                    Console.WriteLine("Arrangement: {0}", flr.Arrangement);
                    Console.WriteLine("Unit Price:  {0:F}", flr.UnitPrice);
                }
              Console.WriteLine("//=//=//=//=//=//=//=//=//=//=//=//=//=//=//");
            }
        }
    }
  2. Execute the application to see the result:
     
    //=//=//=//=//=//=//=//=//=//=//=//=//=//=//
    Total: 5 flower items in current inventory
    --------------------------------------------
    Inventory Summary
    ------------------------
    Flower Information
    Type:        Lilies
    Color:       White
    Arrangement: Bouquet
    Unit Price:  39.95
    ------------------------
    Flower Information
    Type:        Daisies
    Color:       Mixed
    Arrangement: Bouquet
    Unit Price:  40.50
    ------------------------
    Flower Information
    Type:        Carnations
    Color:       Lavender
    Arrangement: Any
    Unit Price:  34.85
    ------------------------
    Flower Information
    Type:        Roses
    Color:       Pink
    Arrangement: Bouquet
    Unit Price:  29.95
    ------------------------
    Flower Information
    Type:        Daisies
    Color:       Yellow
    Arrangement: Vase
    Unit Price:  29.95
    //=//=//=//=//=//=//=//=//=//=//=//=//=//=//
    Press any key to continue . . .
  3. Close the DOS window

 

 

Previous Copyright © 2008-2011 FunctionX Next