views:

805

answers:

2

Hi, this is from Adobe docs:

package {
    import flash.display.Sprite;
    public class Array_filter extends Sprite {
        public function Array_filter() {
            var employees:Array = new Array();
            employees.push({name:"Employee 1", manager:false});
            employees.push({name:"Employee 2", manager:true});
            employees.push({name:"Employee 3", manager:false});
            trace("Employees:");
            employees.forEach(traceEmployee);

            var managers:Array = employees.filter(isManager);
            trace("Managers:");
            managers.forEach(traceEmployee);
        }
        private function isManager(element:*, index:int, arr:Array):Boolean {
            return (element.manager == true);
        }
        private function traceEmployee(element:*, index:int, arr:Array):void {
            trace("\t" + element.name + ((element.manager) ? " (manager)" : ""));
        }
    }
}

The problem is the Array class filter method. It works this way: you pass a function as an argument of filter and an array is returned based on the function you pass. The problem is that it seems you can't add any other parameter. So, if you must create (for example inside a for loop) 4 arrays from the same array and you want to use the same function, you can only test against a property of the class you must previously set to the value you want to test.

Is there any other way to add that parameter?

A: 

You want to use something like Delegates or function binding, or closures. Depending on your coding and terminology preferences. The idea behind all of them is that you create a dynamic function wrapper for the core "filter" function. That wrapper will have access to extra parameters that you pass. So, the first time you call it, you might go:

a.filter(Delegate.create(myFunc, param1));

and the next time:

a.filter(Delegate.create(myFunc, param2));

and you function would have something like this:

private function myFunc(item:*, index:Number, a:Array, param:Object=null):Boolean{}

A quick an dirty method is to just pass an inline function like this:

a.filter(
  function(item:*, index:Number, a:Array):Boolean { 
    return myFunc(item,index,a,param1); 
  }
);

where param1 is passed using the closure created by the function definition.

Glenn
Hi Glenn, and thanks. Do we have Delegates in AS3 too? I could not find them...
Delegates are not part of the AS3 language as a native class. You have to roll your own ( or find a sample online). Just make a class with a static "create" function that returns another function. And the class can keep track of your extra parameters.
Glenn
Very well, thanks.
Hi Glenn, I was thinking that maybe it can be useful Function.apply
fn.apply(...) calls the function immediately, but allows you to pass the arguments as an array. What you want is to bind additional arguments to an existing function for use when it gets executed by the filter.
Glenn
A: 

When filtering by a variable object properties in an array, I wrapped the filtering into another function:

protected function FilterByProperty(input_array:Array, extra_testing:Object):Array
{
    function FilterFunction(element:Object, index:int, array:Array):Boolean
    {
        return element.property == extra_testing; // Arbitrary test
    }

    return input_array.filter(FilterFunction);
}

var filtered_array:Array = FilterByProperty(unfiltered_array, test_property);
Syhon