News + Views

Depth First Tree Flattening with the Yield Keyword in C Sharp

Posted by | Monday, May 17, 2010 | not categorized | Leave comment

A common task when working with tree like data structures is flattening them out into a list. Usually a recursive function is used to flatten out the list, which is then iterated over. However, with the yield keyword (c# 2.0) it's easy make custom trees (or anything else) directly iterable.

The yield keyword usually has an example similar to Listing 1 to show usage.

Listing 1. Basic yield example.

public class List
{
    //using System.Collections;
    public static IEnumerable Power(int number, int exponent)
    {
        int counter = 0;
        int result = 1;
        while (counter++ < exponent)
        {
            result = result * number;
            yield return result;
        }
    }

    static void Main()
    {
        // Display powers of 2 up to the exponent 8:
        foreach (int i in Power(2, 8))
        {
            Console.Write("{0} ", i);
        }
    }
}
/*
Output:
2 4 8 16 32 64 128 256 
*/

This sort of example does not really give an idea of its power. Today, I needed to iterate depth first over a tree, rather than create an explicitly recursive function, I decided to make the class implement IEnumerable and use yield to provide the elements back to the consumer. Listing 2 is a quick demo of the technique I used.

Listing 2. Tree flattening.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IEnumerableTreeWithYield
{
    class Program
    {
        static void Main(string[] args)
        {
            System.Random rnd = new Random();

            Node root = new Node(-1);

            for (int i = 0; i <= 10; i++)
            {
                Node child = new Node(i);
                for (int j = 0; j < i; j++)
                {
                    child.Children.Add(new Node(rnd.Next()));
                }

                root.Children.Add(child);
            }

            foreach (var c in root) // this is using the IEnumerable interface
            {
                Console.WriteLine(c.Value);
            }

            Console.ReadLine();
        }
    }

    class Node : IEnumerable<Node>
    {
        public List<Node> Children { get; set; }
        public int Value { get; set; }
        public Node(int value)
        {
            this.Value = value;
            this.Children = new List<Node>();
        }

        public IEnumerator<Node> GetEnumerator()
        {
            yield return this;

            if (this.Children.Count > 0)
            {
                foreach (var internalChild in this.Children)
                {
                    foreach (var c in internalChild)
                    {
                        yield return c;
                    }
                }
            }
        }

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

The simple foreach loop at line 27 uses the enumerator, and recieves a flattened list of the tree. This seems easier, and probably less error prone, than rolling your own recursion. As an added benefit of this method, because IEnumerable has been implemented, you can use Linq queries against the tree!

Not tagged

 

Leave a Comment

Your name *

Your e-mail address *

Your Message *

Archive

2012    (8)

2011    (19)

2010    (16)

2009    (10)

 
 

Contact Us

 

Governor Technology Limited
91-93 Southwark Street
LondonSE1 0HX
Tel:020 7593 2210
Fax: 020 7620 6172
Email: info@governor.co.uk