Browse Source

Add optional initializer to array.reduce()

VasiliyRyabtsev 7 years ago
parent
commit
04cf1c2ed0
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

@@ -422,9 +422,20 @@ Creates a new array of the same size. For each element in the original array inv
 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

@@ -634,14 +634,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);
@@ -652,6 +659,7 @@ static SQInteger array_reduce(HSQUIRRELVM v)
             res = v->GetUp(-1);
             v->Pop();
         }
+        v->Pop();
     }
     v->Push(res);
     return 1;
@@ -837,7 +845,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}