From 3c3cc43010fe919c9821bcfdb1a0b2d94ab9abeb Mon Sep 17 00:00:00 2001 From: nirvn Date: Mon, 20 Aug 2018 10:42:40 +0700 Subject: [PATCH] [FEATURE] Add generate_series(start,stop,step) expression function The function creates an array containing a sequence of numbers. --- resources/function_help/json/generate_series | 13 ++++++++++ src/core/expression/qgsexpressionfunction.cpp | 25 +++++++++++++++++++ tests/src/core/testqgsexpression.cpp | 17 +++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 resources/function_help/json/generate_series diff --git a/resources/function_help/json/generate_series b/resources/function_help/json/generate_series new file mode 100644 index 00000000000..e366aadd30c --- /dev/null +++ b/resources/function_help/json/generate_series @@ -0,0 +1,13 @@ +{ + "name": "generate_series", + "type": "function", + "description": "Creates an array containing a sequence of numbers.", + "arguments": [ + {"arg":"start", "description":"first value of the sequence"}, + {"arg":"stop", "description":"value that ends the sequence once reached"}, + {"arg":"step","optional":true,"default":"1","description":"value used as the increment between values"} + ], + "examples": [ { "expression":"generate_series('1,5)", "returns":"array: '1', '2', '3', '4', '5'"}, + { "expression":"generate_series('5,1,-1)", "returns":"array: '5', '4', '3', '2', '1'"} + ] +} diff --git a/src/core/expression/qgsexpressionfunction.cpp b/src/core/expression/qgsexpressionfunction.cpp index 9b8d2954aa6..143bc3994ca 100644 --- a/src/core/expression/qgsexpressionfunction.cpp +++ b/src/core/expression/qgsexpressionfunction.cpp @@ -220,6 +220,30 @@ bool QgsExpressionFunction::allParamsStatic( const QgsExpressionNodeFunction *no return true; } +static QVariant fcnGenerateSeries( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * ) +{ + double start = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent ); + double stop = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent ); + double step = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent ); + + if ( step == 0.0 || ( step > 0.0 && start > stop ) || ( step < 0.0 && start < stop ) ) + return QVariant(); + + QVariantList array; + int length = 1; + + array << start; + double current = start + step; + while ( ( ( step > 0.0 && current <= stop ) || ( step < 0.0 && current >= stop ) ) && length <= 1000000 ) + { + array << current; + current += step; + length++; + } + + return array; +} + static QVariant fcnGetVariable( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * ) { if ( !context ) @@ -4724,6 +4748,7 @@ const QList &QgsExpression::Functions() << new QgsStaticExpressionFunction( QStringLiteral( "array_distinct" ), 1, fcnArrayDistinct, QStringLiteral( "Arrays" ) ) << new QgsStaticExpressionFunction( QStringLiteral( "array_to_string" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "delimiter" ), true, "," ) << QgsExpressionFunction::Parameter( QStringLiteral( "emptyvalue" ), true, "" ), fcnArrayToString, QStringLiteral( "Arrays" ) ) << new QgsStaticExpressionFunction( QStringLiteral( "string_to_array" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "delimiter" ), true, "," ) << QgsExpressionFunction::Parameter( QStringLiteral( "emptyvalue" ), true, "" ), fcnStringToArray, QStringLiteral( "Arrays" ) ) + << new QgsStaticExpressionFunction( QStringLiteral( "generate_series" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "start" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "stop" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "step" ), true, 1.0 ), fcnGenerateSeries, QStringLiteral( "Arrays" ) ) //functions for maps << new QgsStaticExpressionFunction( QStringLiteral( "map" ), -1, fcnMap, QStringLiteral( "Maps" ) ) diff --git a/tests/src/core/testqgsexpression.cpp b/tests/src/core/testqgsexpression.cpp index b7a5f88852e..b0d3335b338 100644 --- a/tests/src/core/testqgsexpression.cpp +++ b/tests/src/core/testqgsexpression.cpp @@ -2607,6 +2607,23 @@ class TestQgsExpression: public QObject QCOMPARE( v4, QVariant( "test value" ) ); } + void eval_generate_series() + { + QVariantList array; + array << 1 << 2 << 3 << 4; + QCOMPARE( QgsExpression( "generate_series(1,4)" ).evaluate(), QVariant( array ) ); + array.clear(); + array << 1 << 1.25 << 1.5 << 1.75 << 2; + QCOMPARE( QgsExpression( "generate_series(1,2,0.25)" ).evaluate(), QVariant( array ) ); + array.clear(); + array << 10 << 9 << 8; + QCOMPARE( QgsExpression( "generate_series(10,8,-1)" ).evaluate(), QVariant( array ) ); + + QCOMPARE( QgsExpression( "generate_series(10,11,-1)" ).evaluate(), QVariant() ); + QCOMPARE( QgsExpression( "generate_series(10,5)" ).evaluate(), QVariant() ); + QCOMPARE( QgsExpression( "generate_series(1,2,0)" ).evaluate(), QVariant() ); + } + void eval_string_array() { QgsFeature f( 100 );