diff --git a/src/expressions/functions/builtInFunctions_arrays.ts b/src/expressions/functions/builtInFunctions_arrays.ts index fd122ebcd..f4f772d89 100644 --- a/src/expressions/functions/builtInFunctions_arrays.ts +++ b/src/expressions/functions/builtInFunctions_arrays.ts @@ -460,17 +460,16 @@ const arraySort: FunctionDefinitionType = ( }); }; -function flattenItem(flatteneditems: ISequence, item: Value): ISequence { +function flattenItem(item: Value): ISequence { if (isSubtypeOf(item.type, ValueType.ARRAY)) { - return (item as ArrayValue).members.reduce( - (flatteneditemsOfMember, member) => - member().mapAll((allValues) => - allValues.reduce(flattenItem, flatteneditemsOfMember) - ), - flatteneditems + const arrayItem = item as ArrayValue; + return concatSequences( + arrayItem.members.map((member) => + member().mapAll((subItems) => concatSequences(subItems.map(flattenItem))) + ) ); } - return concatSequences([flatteneditems, sequenceFactory.singleton(item)]); + return sequenceFactory.singleton(item); } const arrayFlatten: FunctionDefinitionType = ( _dynamicContext, @@ -478,7 +477,7 @@ const arrayFlatten: FunctionDefinitionType = ( _staticContext, itemSequence ) => { - return itemSequence.mapAll((items) => items.reduce(flattenItem, sequenceFactory.empty())); + return itemSequence.mapAll((items) => concatSequences(items.map(flattenItem))); }; const declarations: BuiltinDeclarationType[] = [ diff --git a/test/specs/parsing/arrays/arrayFunctions.tests.ts b/test/specs/parsing/arrays/arrayFunctions.tests.ts index d98784308..cfef7b751 100644 --- a/test/specs/parsing/arrays/arrayFunctions.tests.ts +++ b/test/specs/parsing/arrays/arrayFunctions.tests.ts @@ -3,6 +3,7 @@ import { evaluateXPath, evaluateXPathToArray, evaluateXPathToBoolean, + evaluateXPathToNumber, evaluateXPathToNumbers, evaluateXPathToString, evaluateXPathToStrings, @@ -433,6 +434,21 @@ describe('functions over arrays', () => { evaluateXPathToStrings('array:flatten(["a", ["b", "c"], "d"])', documentNode), ['a', 'b', 'c', 'd'] )); + + it('can flatten long arrays', () => + chai.assert.equal( + evaluateXPathToNumber('array:flatten(array{1 to 20000}) => count()', documentNode), + 20000 + )); + + it('can flatten deep arrays', () => + chai.assert.equal( + evaluateXPathToNumber( + '(1 to 200) => fold-left([1], function ($accum, $item) {[$accum, $item]}) => array:flatten() => count()', + documentNode + ), + 201 + )); }); describe('atomizing arrays', () => {