Browse Source

Merge pull request #167 from VasiliyRyabtsev/feature/reduce-initializer

Add optional initializer to array.reduce()
Alberto Demichelis 7 years ago
parent
commit
780e9c96b3
2 changed files with 28 additions and 9 deletions
  1. 14 3
      doc/source/reference/language/builtin_functions.rst
  2. 14 6
      squirrel/sqbaselib.cpp

+ 14 - 3
doc/source/reference/language/builtin_functions.rst

@@ -423,9 +423,20 @@ Provided func can accept up to 3 arguments: array item value (required), array i
 for each element in the array invokes the function 'func' and replace the original value of the element with the return value of the function.
 
 
-.. js:function:: array.reduce(func(prevval,curval))
-
-Reduces an array to a single value. For each element in the array invokes the function 'func' passing the initial value (or value from the previous callback call) and the value of the current element. the return value of the function is then used as 'prevval' for the next element. Given an array of length 0, returns null. Given an array of length 1, returns the first element. Given an array with 2 or more elements calls the function with the first two elements as the parameters, gets that result, then calls the function with that result and the third element, gets that result, calls the function with that result and the fourth parameter and so on until all element have been processed. Finally, returns the return value of the last invocation of func.
+.. js:function:: array.reduce(func(prevval,curval), [initializer])
+
+Reduces an array to a single value. For each element in the array invokes the function 'func' passing
+the initial value (or value from the previous callback call) and the value of the current element.
+The return value of the function is then used as 'prevval' for the next element.
+If the optional initializer is present, it is placed before the items of the array in the calculation,
+and serves as a default when the sequence is empty.
+If initializer is not given then for sequence contains only one item, reduce() returns the first item,
+and for empty sequence returns null.
+
+Given an sequence with 2 or more elements (including initializer) calls the function with the first two elements as the parameters,
+gets that result, then calls the function with that result and the third element, gets that result,
+calls the function with that result and the fourth parameter and so on until all element have been processed.
+Finally, returns the return value of the last invocation of func.
 
 
 .. js:function:: array.filter(func(index,val))

+ 14 - 6
squirrel/sqbaselib.cpp

@@ -654,14 +654,21 @@ static SQInteger array_reduce(HSQUIRRELVM v)
     SQObject &o = stack_get(v,1);
     SQArray *a = _array(o);
     SQInteger size = a->Size();
-    if(size == 0) {
+    SQObjectPtr res;
+    SQInteger iterStart;
+    if (sq_gettop(v)>2) {
+        res = stack_get(v,3);
+        iterStart = 0;
+    } else if (size==0) {
         return 0;
+    } else {
+        a->Get(0,res);
+        iterStart = 1;
     }
-    SQObjectPtr res;
-    a->Get(0,res);
-    if(size > 1) {
+    if (size > iterStart) {
         SQObjectPtr other;
-        for(SQInteger n = 1; n < size; n++) {
+        v->Push(stack_get(v,2));
+        for (SQInteger n = iterStart; n < size; n++) {
             a->Get(n,other);
             v->Push(o);
             v->Push(res);
@@ -672,6 +679,7 @@ static SQInteger array_reduce(HSQUIRRELVM v)
             res = v->GetUp(-1);
             v->Pop();
         }
+        v->Pop();
     }
     v->Push(res);
     return 1;
@@ -857,7 +865,7 @@ const SQRegFunction SQSharedState::_array_default_delegate_funcz[]={
     {_SC("clear"),obj_clear,1, _SC(".")},
     {_SC("map"),array_map,2, _SC("ac")},
     {_SC("apply"),array_apply,2, _SC("ac")},
-    {_SC("reduce"),array_reduce,2, _SC("ac")},
+    {_SC("reduce"),array_reduce,-2, _SC("ac.")},
     {_SC("filter"),array_filter,2, _SC("ac")},
     {_SC("find"),array_find,2, _SC("a.")},
     {NULL,(SQFUNCTION)0,0,NULL}