Browse Source

add Array.reduce (closes #4637)

Dan Korostelev 9 years ago
parent
commit
5bc2b68e10

+ 1 - 1
genswf9.ml

@@ -315,7 +315,7 @@ let property ctx p t =
 		(match p with
 		| "length" -> ident p, Some KInt, false (* UInt in the spec *)
 		| "map" | "filter" when Common.defined ctx.com Define.NoFlashOverride -> ident (p ^ "HX"), None, true
-		| "copy" | "insert" | "remove" | "iterator" | "toString" | "map" | "filter" -> ident p , None, true
+		| "copy" | "insert" | "remove" | "iterator" | "toString" | "map" | "filter" | "reduce" -> ident p , None, true
 		| _ -> as3 p, None, false);
 	| TInst ({ cl_path = ["flash"],"Vector" },_) ->
 		(match p with

+ 14 - 0
std/Array.hx

@@ -273,6 +273,20 @@ extern class Array<T> {
 	**/
 	function map<S>( f : T -> S ) : Array<S>;
 
+	/**
+		Reduce elements of `this` array to a single value by calling function `f`.
+
+		The `f` function receives two arguments:
+		 - the value, returned by the previous call of `f`
+		   or `first` if this is a first call
+		 - current element of `this` array being processed, in order
+
+		If `this` array is empty, `first` is returned.
+
+		If `f` is null, the result is unspecified.
+	**/
+	function reduce<S>( f : S -> T -> S, first : S ) : S;
+
 	/**
 		Returns an Array containing those elements of `this` for which `f`
 		returned true.

+ 6 - 0
std/cs/_std/Array.hx

@@ -406,6 +406,12 @@ import cs.NativeArray;
 		return ret;
 	}
 
+	public function reduce<S>( f : S -> T -> S, v : S ) : S {
+		for (elt in this)
+			v = f(v, elt);
+		return v;
+	}
+
 	public function filter( f : T -> Bool ) : Array<T> {
 		var ret = [];
 		for (elt in this)

+ 6 - 0
std/flash/Boot.hx

@@ -239,6 +239,11 @@ class Boot extends flash.display.MovieClip {
 		aproto.insert = function(i,x) {
 			__this__.splice(i,0,x);
 		};
+		aproto.reduce = function(f,v) {
+			for (i in 0...__this__.length)
+				v = f(v, __this__[i]);
+			return v;
+		};
 		aproto.remove = function(obj) {
 			var idx = __this__.indexOf(obj);
 			if( idx == -1 ) return false;
@@ -259,6 +264,7 @@ class Boot extends flash.display.MovieClip {
 		};
 		aproto.setPropertyIsEnumerable("copy", false);
 		aproto.setPropertyIsEnumerable("insert", false);
+		aproto.setPropertyIsEnumerable("reduce", false);
 		aproto.setPropertyIsEnumerable("remove", false);
 		aproto.setPropertyIsEnumerable("iterator", false);
 		#if (as3 || no_flash_override)

+ 6 - 0
std/java/_std/Array.hx

@@ -414,6 +414,12 @@ import java.NativeArray;
 		return ret;
 	}
 
+	public function reduce<S>( f : S -> T -> S, v : S ) : S {
+		for (elt in this)
+			v = f(v, elt);
+		return v;
+	}
+
 	public function filter( f : T -> Bool ) : Array<T> {
 		var ret = [];
 		for (elt in this)

+ 5 - 0
std/js/_std/Array.hx

@@ -48,6 +48,7 @@ extern class Array<T> {
 #if js_es5
 	function indexOf( x : T, ?fromIndex:Int ) : Int;
 	function lastIndexOf( x : T, ?fromIndex:Int ) : Int;
+	function reduce<S>( f : S -> T -> S, first : S ) : S;
 
 #else
 	inline function indexOf( x : T, ?fromIndex:Int ) : Int {
@@ -57,6 +58,10 @@ extern class Array<T> {
 	inline function lastIndexOf( x : T, ?fromIndex:Int ) : Int {
 		return @:privateAccess HxOverrides.lastIndexOf(this,x,(fromIndex!=null)?fromIndex:length-1);
 	}
+
+	inline function reduce<S>( f : S -> T -> S, first : S ) : S {
+		return @:privateAccess HxOverrides.reduce(this, f, first);
+	}
 #end
 
 	inline function copy() : Array<T> {

+ 6 - 0
std/js/_std/HxOverrides.hx

@@ -117,6 +117,12 @@ class HxOverrides {
 		return -1;
 	}
 
+	static function reduce<T,S>( a : Array<T>, f : S -> T -> S, v : S ) : S {
+		for (el in a)
+			v = f(v, el);
+		return v;
+	}
+
 	static function remove<T>( a : Array<T>, obj : T ) {
 		var i = a.indexOf(obj);
 		if( i == -1 ) return false;

+ 6 - 0
std/neko/_std/Array.hx

@@ -276,6 +276,12 @@
 		return ret;
 	}
 
+	public function reduce<S>( f : S -> T -> S, v : S ) : S {
+		for (elt in this)
+			v = f(v, elt);
+		return v;
+	}
+
 	public function filter( f : T -> Bool ) : Array<T> {
 		var ret = [];
 		for (elt in this)

+ 4 - 0
std/php/Boot.hx

@@ -191,6 +191,10 @@ class _hx_array implements ArrayAccess, IteratorAggregate {
 		return new _hx_array(array_map($f, $this->a));
 	}
 
+	function reduce($f, $first) {
+		return array_reduce($this->a, $f, $first);
+	}
+
 	function filter($f) {
 		return new _hx_array(array_values(array_filter($this->a,$f)));
 	}

+ 1 - 0
std/python/Boot.hx

@@ -301,6 +301,7 @@ class Boot {
 			case "length" if (isArray(o)): return ArrayImpl.get_length(o);
 			case "map" if (isArray(o)): return ArrayImpl.map.bind(o);
 			case "filter" if (isArray(o)): return ArrayImpl.filter.bind(o);
+			case "reduce" if (isArray(o)): return ArrayImpl.reduce.bind(o);
 			case "concat" if (isArray(o)): return ArrayImpl.concat.bind(o);
 			case "copy" if (isArray(o)): return function () return ArrayImpl.copy(o);
 			case "iterator" if (isArray(o)): return ArrayImpl.iterator.bind(o);

+ 4 - 0
std/python/_std/Array.hx

@@ -112,6 +112,10 @@ extern class Array<T> implements ArrayAccess<T> {
 		return ArrayImpl.filter(this,f);
 	}
 
+	@:runtime public inline function reduce<S>( f : S -> T -> S, first : S ) : S {
+		return ArrayImpl.reduce(this,f,first);
+	}
+
 	@:keep private inline function _get(idx:Int):T
 	{
 		return ArrayImpl._get(this, idx);

+ 5 - 0
std/python/internal/ArrayImpl.hx

@@ -144,6 +144,11 @@ class ArrayImpl {
 		return UBuiltins.list(UBuiltins.filter(f, cast x));
 	}
 
+	@:ifFeature("dynamic_read.reduce", "anon_optional_read.reduce")
+	public static inline function reduce<T,S>(x:Array<T>, f : S -> T -> S, v : S) : S {
+		return python.lib.Functools.reduce(f, x, v);
+	}
+
 	@:ifFeature("dynamic_read.insert", "anon_optional_read.insert")
 	public static inline function insert<T>(a:Array<T>, pos : Int, x : T ) : Void {
 		Syntax.callField(a, "insert", pos, x);

+ 2 - 1
std/python/lib/Functools.hx

@@ -25,6 +25,7 @@ package python.lib;
 @:pythonImport("functools")
 extern class Functools {
 
-	public static function cmp_to_key<A>(f:A->A->Int):Dynamic;
+	static function cmp_to_key<A>(f:A->A->Int):Dynamic;
+	static function reduce<T,S>(f:S->T->S, a:Array<T>, ?initializer:S):S;
 
 }

+ 4 - 0
tests/unit/src/unitstd/Array.unit.hx

@@ -271,6 +271,10 @@ var values = [];
 for (a in arr) values.push(a.id);
 values == [1, 3, 5];
 
+// reduce
+[1,2,3].reduce(function(a:Int, b:Int) return a + b, 1) == 7;
+[1,2,3].reduce(function(a:String, b:Int) return a + b, "0") == "0123";
+
 #if !as3
 // check that map and filter work well on Dynamic as well
 var a : Dynamic = [0,1,2];