Examples

You can iterate over your own Data Structures, by providing an iterator function.

class MyClass 
{
    public var names:Array<String>;

    public function new () 
    {
        names = ["ted", "fred", "tim"];
    }

    public function iterator ()
    {
        return names.iterator();
    }
}

class Test
{
    public static function main ()
    {
        var myInstance = new MyClass();

        for (i in myInstance)
            trace(i); // ted, fred, tim
    }
}

The Iterable Typedef is really powerful, it also enables you to iterate a Class:

class MyClass 
{
    public static var names = ["ted", "fred", "tim"];

    public static function iterator ()
    {
        return names.iterator();
    }
}

class Test 
{
    public static function main ()
    {
        for (i in MyClass)
            trace(i); // ted, fred, tim
    }
}

Combining Iterator and Iterable

'while' and 'for' loops can often end up quite messy, Lambda mapping of a custom Iterable structure can produce a clearer alternative allowing us to hide some implementation details ( sometimes platfrom sepecific ) in the Iterable.
Although it sounds complex we are just mapping a collection to a new Array of changed elements. The Lambda.map static method take an Iterable Object and a function and applies the function to each of it's elements and returns us an array of these changed elements.
To create your own Iterable structure we can create an Iterator and then add an Iterator method that returns the instance of the Iterator! Suppose we wanted to get all the char codes for a word. Now the obvious way might be to use a for loop.

 
    var str = 'hello';
    var out = '';
    for( i in 0...str.length )
    {
        out += str.charCodeAt( i ) +'\n';
    }

But we could also do this by creating a custom Iterable.
    class CharCodeIterable
    {
        public var length: Int;
        private var count: Int;
        private var str: String;
        public function new( str_: String ) {
            count = 0;
            length = str_.length;
            str = str_;   
        }
        public function iterator ():Iterator<Int> { 
                return this;                 
        }
        public function hasNext(): Bool {
                 return count < length;
        }
        public function next(): Int { 
                 return str.charCodeAt( count++ ); 
        }   
    }

Notice how we have used the next to hide an implementation detail that clutters our original for loop. Next we can use this class to produce the same result as the original for loop but instead utilizing Lambda.map.
var arr = Lambda.map
(     
    new CharCodeIterable('hello')
    , function( charCode: Int ):String {{ return  charCode + '\n' ;} 
);
trace( arr.join('') );  

Inheritance to reduce the effort of creating custom Iterable


Now this seems a lot of work to create a custom Iterable, but we can create a more generic Iterable that can be used as a base of many custom Iterable's.
class IterableGeneric< A, B >
{
    public var length: Int;
    private var count: Int;
    private var in_structure: A;
    private function new( in_structure_: A ){
        count = 0;
        in_structure= in_structure_;
    } 
    public function iterator ():Iterator<B> { return this; }
    public function hasNext(): Bool { return count < length; }
}

And so our CharCodeIterable is now much faster to write, and we avoid much of the boiler plate code.
class CharCodeIterable extends IterableGeneric< String, Int >
{
    public function new( str_: String ) 
    {
        length = str_.length;   
        super( str_ );
    }
    public function next(): Int
    {  
        return in_structure.charCodeAt( count++ );
    }   
}

It is also possible to iterate over floating ranges, and to reverse the step order. In most case a while loop is probably going to be faster approach, but custom Iterable classes are a powerful functional concept that may add clarity and structure to your code.

Float Iterate


Sometimes we wish to Iterate over a range of Floats.
class IterateFloatRange<Float>
{
    private var min: Float;
    private var max: Float;
    private var step: Float;
    private var count: Float;
    public function new ( min_: Float, max_: Float, step_: Float )
        {
        min = min_;
        max = max_;
        step = step_;
        count = min_- step_;
        }
        public function iterator ():Iterator<Float> { 
                return this;                 
        }
    public function hasNext(): Bool {
                 return count < max;
        }
    public function next(): Float
    {
        count += step;
        return count;
    }
}

And we can use it
var aRange = new IterateFloatRange( 0.5, 1.5, 0.1 );
for (f in aRange ) { trace(f); }
version #15547, modified 2012-10-05 03:06:29 by JLM
0 comment