QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
qgsaggregatecalculator.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsaggregatecalculator.cpp
3 --------------------------
4 begin : May 2016
5 copyright : (C) 2016 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19#include "qgsexpressionutils.h"
20#include "qgsfeature.h"
21#include "qgsfeaturerequest.h"
22#include "qgsfeatureiterator.h"
23#include "qgsgeometry.h"
24#include "qgsvectorlayer.h"
25
26
27
29 : mLayer( layer )
30{
31
32}
33
35{
36 return mLayer;
37}
38
40{
41 mFilterExpression = parameters.filter;
42 mDelimiter = parameters.delimiter;
43 mOrderBy = parameters.orderBy;
44}
45
47{
48 mFidsSet = true;
49 mFidsFilter = fids;
50}
51
53 const QString &fieldOrExpression, QgsExpressionContext *context, bool *ok, QgsFeedback *feedback ) const
54{
55 mLastError.clear();
56 if ( ok )
57 *ok = false;
58
60
61 if ( !mLayer )
62 return QVariant();
63
64 QgsExpressionContext defaultContext = mLayer->createExpressionContext();
65 context = context ? context : &defaultContext;
66
67 std::unique_ptr<QgsExpression> expression;
68
69 const int attrNum = QgsExpression::expressionToLayerFieldIndex( fieldOrExpression, mLayer );
70 if ( attrNum == -1 )
71 {
72 Q_ASSERT( context );
73 context->setFields( mLayer->fields() );
74 // try to use expression
75 expression.reset( new QgsExpression( fieldOrExpression ) );
76
77 if ( expression->hasParserError() || !expression->prepare( context ) )
78 {
79 mLastError = !expression->parserErrorString().isEmpty() ? expression->parserErrorString() : expression->evalErrorString();
80 return QVariant();
81 }
82 }
83
84 QSet<QString> lst;
85 if ( !expression )
86 lst.insert( mLayer->fields().at( attrNum ).name() );
87 else
88 lst = expression->referencedColumns();
89
90 request.setFlags( ( expression && expression->needsGeometry() ) ?
93 .setSubsetOfAttributes( lst, mLayer->fields() );
94
95 if ( mFidsSet )
96 request.setFilterFids( mFidsFilter );
97
98 if ( !mOrderBy.empty() )
99 request.setOrderBy( mOrderBy );
100
101 if ( !mFilterExpression.isEmpty() )
102 request.setFilterExpression( mFilterExpression );
103 if ( context )
104 request.setExpressionContext( *context );
105
106 request.setFeedback( feedback ? feedback : ( context ? context->feedback() : nullptr ) );
107
108 //determine result type
109 QVariant::Type resultType = QVariant::Double;
110 int userType = 0;
111 if ( attrNum == -1 )
112 {
113 if ( aggregate == GeometryCollect )
114 {
115 // in this case we know the result should be a geometry value, so no need to sniff it out...
116 resultType = QVariant::UserType;
117 }
118 else
119 {
120 // check expression result type
121 bool foundFeatures = false;
122 std::tuple<QVariant::Type, int> returnType = QgsExpressionUtils::determineResultType( fieldOrExpression, mLayer, request, *context, &foundFeatures );
123 if ( !foundFeatures )
124 {
125 if ( ok )
126 *ok = true;
127 return defaultValue( aggregate );
128 }
129
130 resultType = std::get<0>( returnType );
131 userType = std::get<1>( returnType );
132 if ( resultType == QVariant::Invalid )
133 {
134 QVariant v;
135 switch ( aggregate )
136 {
137 // string
142 v = QString();
143 break;
144
145 // numerical
146 case Sum:
147 case Mean:
148 case Median:
149 case StDev:
150 case StDevSample:
151 case Range:
152 case FirstQuartile:
153 case ThirdQuartile:
155 // mixed type, fallback to numerical
156 case Count:
157 case CountDistinct:
158 case CountMissing:
159 case Minority:
160 case Majority:
161 case Min:
162 case Max:
163 v = 0.0;
164 break;
165
166 // geometry
167 case GeometryCollect:
168 v = QgsGeometry();
169 break;
170
171 // list, fallback to string
172 case ArrayAggregate:
173 v = QString();
174 break;
175 }
176 resultType = v.type();
177 userType = v.userType();
178 }
179 }
180 }
181 else
182 resultType = mLayer->fields().at( attrNum ).type();
183
184 QgsFeatureIterator fit = mLayer->getFeatures( request );
185 return calculate( aggregate, fit, resultType, userType, attrNum, expression.get(), mDelimiter, context, ok, &mLastError );
186}
187
189{
190 const QString normalized = string.trimmed().toLower();
191
192 if ( ok )
193 *ok = true;
194
195 if ( normalized == QLatin1String( "count" ) )
196 return Count;
197 else if ( normalized == QLatin1String( "count_distinct" ) )
198 return CountDistinct;
199 else if ( normalized == QLatin1String( "count_missing" ) )
200 return CountMissing;
201 else if ( normalized == QLatin1String( "min" ) )
202 return Min;
203 else if ( normalized == QLatin1String( "max" ) )
204 return Max;
205 else if ( normalized == QLatin1String( "sum" ) )
206 return Sum;
207 else if ( normalized == QLatin1String( "mean" ) )
208 return Mean;
209 else if ( normalized == QLatin1String( "median" ) )
210 return Median;
211 else if ( normalized == QLatin1String( "stdev" ) )
212 return StDev;
213 else if ( normalized == QLatin1String( "stdevsample" ) )
214 return StDevSample;
215 else if ( normalized == QLatin1String( "range" ) )
216 return Range;
217 else if ( normalized == QLatin1String( "minority" ) )
218 return Minority;
219 else if ( normalized == QLatin1String( "majority" ) )
220 return Majority;
221 else if ( normalized == QLatin1String( "q1" ) )
222 return FirstQuartile;
223 else if ( normalized == QLatin1String( "q3" ) )
224 return ThirdQuartile;
225 else if ( normalized == QLatin1String( "iqr" ) )
226 return InterQuartileRange;
227 else if ( normalized == QLatin1String( "min_length" ) )
228 return StringMinimumLength;
229 else if ( normalized == QLatin1String( "max_length" ) )
230 return StringMaximumLength;
231 else if ( normalized == QLatin1String( "concatenate" ) )
232 return StringConcatenate;
233 else if ( normalized == QLatin1String( "concatenate_unique" ) )
235 else if ( normalized == QLatin1String( "collect" ) )
236 return GeometryCollect;
237 else if ( normalized == QLatin1String( "array_agg" ) )
238 return ArrayAggregate;
239
240 if ( ok )
241 *ok = false;
242
243 return Count;
244}
245
247{
248 switch ( aggregate )
249 {
251 return QObject::tr( "count" );
253 return QObject::tr( "count distinct" );
255 return QObject::tr( "count missing" );
257 return QObject::tr( "minimum" );
259 return QObject::tr( "maximum" );
261 return QObject::tr( "sum" );
263 return QObject::tr( "mean" );
265 return QObject::tr( "median" );
267 return QObject::tr( "standard deviation" );
269 return QObject::tr( "standard deviation (sample)" );
271 return QObject::tr( "range" );
273 return QObject::tr( "minority" );
275 return QObject::tr( "majority" );
277 return QObject::tr( "first quartile" );
279 return QObject::tr( "third quartile" );
281 return QObject::tr( "inter quartile range" );
283 return QObject::tr( "minimum length" );
285 return QObject::tr( "maximum length" );
287 return QObject::tr( "concatenate" );
289 return QObject::tr( "collection" );
291 return QObject::tr( "array aggregate" );
293 return QObject::tr( "concatenate (unique)" );
294 }
295 return QString();
296}
297
298QList<QgsAggregateCalculator::AggregateInfo> QgsAggregateCalculator::aggregates()
299{
300 QList< AggregateInfo > aggregates;
303 {
304 QStringLiteral( "count" ),
305 QCoreApplication::tr( "Count" ),
306 QSet<QVariant::Type>()
307 << QVariant::DateTime
308 << QVariant::Date
309 << QVariant::Int
310 << QVariant::UInt
311 << QVariant::LongLong
312 << QVariant::ULongLong
313 << QVariant::String
314 }
316 {
317 QStringLiteral( "count_distinct" ),
318 QCoreApplication::tr( "Count Distinct" ),
319 QSet<QVariant::Type>()
320 << QVariant::DateTime
321 << QVariant::Date
322 << QVariant::UInt
323 << QVariant::Int
324 << QVariant::LongLong
325 << QVariant::ULongLong
326 << QVariant::String
327 }
329 {
330 QStringLiteral( "count_missing" ),
331 QCoreApplication::tr( "Count Missing" ),
332 QSet<QVariant::Type>()
333 << QVariant::DateTime
334 << QVariant::Date
335 << QVariant::Int
336 << QVariant::UInt
337 << QVariant::LongLong
338 << QVariant::String
339 }
341 {
342 QStringLiteral( "min" ),
343 QCoreApplication::tr( "Min" ),
344 QSet<QVariant::Type>()
345 << QVariant::DateTime
346 << QVariant::Date
347 << QVariant::Int
348 << QVariant::UInt
349 << QVariant::LongLong
350 << QVariant::ULongLong
351 << QVariant::Double
352 << QVariant::String
353 }
355 {
356 QStringLiteral( "max" ),
357 QCoreApplication::tr( "Max" ),
358 QSet<QVariant::Type>()
359 << QVariant::DateTime
360 << QVariant::Date
361 << QVariant::Int
362 << QVariant::UInt
363 << QVariant::LongLong
364 << QVariant::ULongLong
365 << QVariant::Double
366 << QVariant::String
367 }
369 {
370 QStringLiteral( "sum" ),
371 QCoreApplication::tr( "Sum" ),
372 QSet<QVariant::Type>()
373 << QVariant::Int
374 << QVariant::UInt
375 << QVariant::LongLong
376 << QVariant::ULongLong
377 << QVariant::Double
378 }
380 {
381 QStringLiteral( "mean" ),
382 QCoreApplication::tr( "Mean" ),
383 QSet<QVariant::Type>()
384 << QVariant::Int
385 << QVariant::UInt
386 << QVariant::LongLong
387 << QVariant::ULongLong
388 << QVariant::Double
389 }
391 {
392 QStringLiteral( "median" ),
393 QCoreApplication::tr( "Median" ),
394 QSet<QVariant::Type>()
395 << QVariant::Int
396 << QVariant::UInt
397 << QVariant::Double
398 }
400 {
401 QStringLiteral( "stdev" ),
402 QCoreApplication::tr( "Stdev" ),
403 QSet<QVariant::Type>()
404 << QVariant::Int
405 << QVariant::UInt
406 << QVariant::LongLong
407 << QVariant::ULongLong
408 << QVariant::Double
409 }
411 {
412 QStringLiteral( "stdevsample" ),
413 QCoreApplication::tr( "Stdev Sample" ),
414 QSet<QVariant::Type>()
415 << QVariant::Int
416 << QVariant::UInt
417 << QVariant::LongLong
418 << QVariant::ULongLong
419 << QVariant::Double
420 }
422 {
423 QStringLiteral( "range" ),
424 QCoreApplication::tr( "Range" ),
425 QSet<QVariant::Type>()
426 << QVariant::Date
427 << QVariant::DateTime
428 << QVariant::Int
429 << QVariant::UInt
430 << QVariant::LongLong
431 << QVariant::ULongLong
432 << QVariant::Double
433 }
435 {
436 QStringLiteral( "minority" ),
437 QCoreApplication::tr( "Minority" ),
438 QSet<QVariant::Type>()
439 << QVariant::Int
440 << QVariant::UInt
441 << QVariant::LongLong
442 << QVariant::ULongLong
443 << QVariant::Double
444 << QVariant::String
445 }
447 {
448 QStringLiteral( "majority" ),
449 QCoreApplication::tr( "Majority" ),
450 QSet<QVariant::Type>()
451 << QVariant::Int
452 << QVariant::UInt
453 << QVariant::LongLong
454 << QVariant::ULongLong
455 << QVariant::Double
456 << QVariant::String
457 }
459 {
460 QStringLiteral( "q1" ),
461 QCoreApplication::tr( "Q1" ),
462 QSet<QVariant::Type>()
463 << QVariant::Int
464 << QVariant::UInt
465 << QVariant::LongLong
466 << QVariant::ULongLong
467 << QVariant::Double
468 }
470 {
471 QStringLiteral( "q3" ),
472 QCoreApplication::tr( "Q3" ),
473 QSet<QVariant::Type>()
474 << QVariant::Int
475 << QVariant::UInt
476 << QVariant::LongLong
477 << QVariant::ULongLong
478 << QVariant::Double
479 }
481 {
482 QStringLiteral( "iqr" ),
483 QCoreApplication::tr( "InterQuartileRange" ),
484 QSet<QVariant::Type>()
485 << QVariant::Int
486 << QVariant::UInt
487 << QVariant::LongLong
488 << QVariant::ULongLong
489 << QVariant::Double
490 }
492 {
493 QStringLiteral( "min_length" ),
494 QCoreApplication::tr( "Min Length" ),
495 QSet<QVariant::Type>()
496 << QVariant::String
497 }
499 {
500 QStringLiteral( "max_length" ),
501 QCoreApplication::tr( "Max Length" ),
502 QSet<QVariant::Type>()
503 << QVariant::String
504 }
506 {
507 QStringLiteral( "concatenate" ),
508 QCoreApplication::tr( "Concatenate" ),
509 QSet<QVariant::Type>()
510 << QVariant::String
511 }
513 {
514 QStringLiteral( "collect" ),
515 QCoreApplication::tr( "Collect" ),
516 QSet<QVariant::Type>()
517 }
519 {
520 QStringLiteral( "array_agg" ),
521 QCoreApplication::tr( "Array Aggregate" ),
522 QSet<QVariant::Type>()
523 };
524
525 return aggregates;
526}
527
528QVariant QgsAggregateCalculator::calculate( QgsAggregateCalculator::Aggregate aggregate, QgsFeatureIterator &fit, QVariant::Type resultType, int userType,
529 int attr, QgsExpression *expression, const QString &delimiter, QgsExpressionContext *context, bool *ok, QString *error )
530{
531 if ( ok )
532 *ok = false;
533
535 {
536 if ( ok )
537 *ok = true;
538 return calculateArrayAggregate( fit, attr, expression, context );
539 }
540
541 switch ( resultType )
542 {
543 case QVariant::Int:
544 case QVariant::UInt:
545 case QVariant::LongLong:
546 case QVariant::ULongLong:
547 case QVariant::Double:
548 {
549 bool statOk = false;
550 const QgsStatisticalSummary::Statistic stat = numericStatFromAggregate( aggregate, &statOk );
551 if ( !statOk )
552 {
553 if ( error )
554 *error = expression ? QObject::tr( "Cannot calculate %1 on numeric values" ).arg( displayName( aggregate ) )
555 : QObject::tr( "Cannot calculate %1 on numeric fields" ).arg( displayName( aggregate ) );
556 return QVariant();
557 }
558
559 if ( ok )
560 *ok = true;
561 return calculateNumericAggregate( fit, attr, expression, context, stat );
562 }
563
564 case QVariant::Date:
565 case QVariant::DateTime:
566 {
567 bool statOk = false;
568 const QgsDateTimeStatisticalSummary::Statistic stat = dateTimeStatFromAggregate( aggregate, &statOk );
569 if ( !statOk )
570 {
571 if ( error )
572 *error = ( expression ? QObject::tr( "Cannot calculate %1 on %2 values" ).arg( displayName( aggregate ) ) :
573 QObject::tr( "Cannot calculate %1 on %2 fields" ).arg( displayName( aggregate ) ) ).arg( resultType == QVariant::Date ? QObject::tr( "date" ) : QObject::tr( "datetime" ) );
574 return QVariant();
575 }
576
577 if ( ok )
578 *ok = true;
579 return calculateDateTimeAggregate( fit, attr, expression, context, stat );
580 }
581
582 case QVariant::UserType:
583 {
584 if ( aggregate == GeometryCollect )
585 {
586 if ( ok )
587 *ok = true;
588 return calculateGeometryAggregate( fit, expression, context );
589 }
590 else
591 {
592 return QVariant();
593 }
594 }
595
596 default:
597 {
598 // treat as string
599 if ( aggregate == StringConcatenate )
600 {
601 //special case
602 if ( ok )
603 *ok = true;
604 return concatenateStrings( fit, attr, expression, context, delimiter );
605 }
606 else if ( aggregate == StringConcatenateUnique )
607 {
608 //special case
609 if ( ok )
610 *ok = true;
611 return concatenateStrings( fit, attr, expression, context, delimiter, true );
612 }
613
614 bool statOk = false;
615 const QgsStringStatisticalSummary::Statistic stat = stringStatFromAggregate( aggregate, &statOk );
616 if ( !statOk )
617 {
618 QString typeString;
619 if ( resultType == QVariant::Invalid )
620 typeString = QObject::tr( "null" );
621 else if ( resultType == QVariant::UserType )
622 typeString = QMetaType::typeName( userType );
623 else
624 typeString = resultType == QVariant::String ? QObject::tr( "string" ) : QVariant::typeToName( resultType );
625
626 if ( error )
627 *error = expression ? QObject::tr( "Cannot calculate %1 on %3 values" ).arg( displayName( aggregate ), typeString )
628 : QObject::tr( "Cannot calculate %1 on %3 fields" ).arg( displayName( aggregate ), typeString );
629 return QVariant();
630 }
631
632 if ( ok )
633 *ok = true;
634 return calculateStringAggregate( fit, attr, expression, context, stat );
635 }
636 }
637
638#ifndef _MSC_VER
639 return QVariant();
640#endif
641}
642
643QgsStatisticalSummary::Statistic QgsAggregateCalculator::numericStatFromAggregate( QgsAggregateCalculator::Aggregate aggregate, bool *ok )
644{
645 if ( ok )
646 *ok = true;
647
648 switch ( aggregate )
649 {
650 case Count:
652 case CountDistinct:
654 case CountMissing:
656 case Min:
658 case Max:
660 case Sum:
662 case Mean:
664 case Median:
666 case StDev:
668 case StDevSample:
670 case Range:
672 case Minority:
674 case Majority:
676 case FirstQuartile:
678 case ThirdQuartile:
686 case GeometryCollect:
687 case ArrayAggregate:
688 {
689 if ( ok )
690 *ok = false;
692 }
693 }
694
695 if ( ok )
696 *ok = false;
698}
699
700QgsStringStatisticalSummary::Statistic QgsAggregateCalculator::stringStatFromAggregate( QgsAggregateCalculator::Aggregate aggregate, bool *ok )
701{
702 if ( ok )
703 *ok = true;
704
705 switch ( aggregate )
706 {
707 case Count:
709 case CountDistinct:
711 case CountMissing:
713 case Min:
715 case Max:
721 case Minority:
723 case Majority:
725
726 case Sum:
727 case Mean:
728 case Median:
729 case StDev:
730 case StDevSample:
731 case Range:
732 case FirstQuartile:
733 case ThirdQuartile:
737 case GeometryCollect:
738 case ArrayAggregate:
739 {
740 if ( ok )
741 *ok = false;
743 }
744 }
745
746 if ( ok )
747 *ok = false;
749}
750
751QgsDateTimeStatisticalSummary::Statistic QgsAggregateCalculator::dateTimeStatFromAggregate( QgsAggregateCalculator::Aggregate aggregate, bool *ok )
752{
753 if ( ok )
754 *ok = true;
755
756 switch ( aggregate )
757 {
758 case Count:
760 case CountDistinct:
762 case CountMissing:
764 case Min:
766 case Max:
768 case Range:
770
771 case Sum:
772 case Mean:
773 case Median:
774 case StDev:
775 case StDevSample:
776 case Minority:
777 case Majority:
778 case FirstQuartile:
779 case ThirdQuartile:
785 case GeometryCollect:
786 case ArrayAggregate:
787 {
788 if ( ok )
789 *ok = false;
791 }
792 }
793
794 if ( ok )
795 *ok = false;
797}
798
799QVariant QgsAggregateCalculator::calculateNumericAggregate( QgsFeatureIterator &fit, int attr, QgsExpression *expression,
801{
802 Q_ASSERT( expression || attr >= 0 );
803
804 QgsStatisticalSummary s( stat );
805 QgsFeature f;
806
807 while ( fit.nextFeature( f ) )
808 {
809 if ( expression )
810 {
811 Q_ASSERT( context );
812 context->setFeature( f );
813 const QVariant v = expression->evaluate( context );
814 s.addVariant( v );
815 }
816 else
817 {
818 s.addVariant( f.attribute( attr ) );
819 }
820 }
821 s.finalize();
822 const double val = s.statistic( stat );
823 return std::isnan( val ) ? QVariant() : val;
824}
825
826QVariant QgsAggregateCalculator::calculateStringAggregate( QgsFeatureIterator &fit, int attr, QgsExpression *expression,
828{
829 Q_ASSERT( expression || attr >= 0 );
830
832 QgsFeature f;
833
834 while ( fit.nextFeature( f ) )
835 {
836 if ( expression )
837 {
838 Q_ASSERT( context );
839 context->setFeature( f );
840 const QVariant v = expression->evaluate( context );
841 s.addValue( v );
842 }
843 else
844 {
845 s.addValue( f.attribute( attr ) );
846 }
847 }
848 s.finalize();
849 return s.statistic( stat );
850}
851
852QVariant QgsAggregateCalculator::calculateGeometryAggregate( QgsFeatureIterator &fit, QgsExpression *expression, QgsExpressionContext *context )
853{
854 Q_ASSERT( expression );
855
856 QgsFeature f;
857 QVector< QgsGeometry > geometries;
858 while ( fit.nextFeature( f ) )
859 {
860 Q_ASSERT( context );
861 context->setFeature( f );
862 const QVariant v = expression->evaluate( context );
863 if ( v.userType() == QMetaType::type( "QgsGeometry" ) )
864 {
865 geometries << v.value<QgsGeometry>();
866 }
867 }
868
869 return QVariant::fromValue( QgsGeometry::collectGeometry( geometries ) );
870}
871
872QVariant QgsAggregateCalculator::concatenateStrings( QgsFeatureIterator &fit, int attr, QgsExpression *expression,
873 QgsExpressionContext *context, const QString &delimiter, bool unique )
874{
875 Q_ASSERT( expression || attr >= 0 );
876
877 QgsFeature f;
878 QStringList results;
879 while ( fit.nextFeature( f ) )
880 {
881 QString result;
882 if ( expression )
883 {
884 Q_ASSERT( context );
885 context->setFeature( f );
886 const QVariant v = expression->evaluate( context );
887 result = v.toString();
888 }
889 else
890 {
891 result = f.attribute( attr ).toString();
892 }
893
894 if ( !unique || !results.contains( result ) )
895 results << result;
896 }
897
898 return results.join( delimiter );
899}
900
901QVariant QgsAggregateCalculator::defaultValue( QgsAggregateCalculator::Aggregate aggregate ) const
902{
903 // value to return when NO features are aggregated:
904 switch ( aggregate )
905 {
906 // sensible values:
907 case Count:
908 case CountDistinct:
909 case CountMissing:
910 return 0;
911
914 return ""; // zero length string - not null!
915
916 case ArrayAggregate:
917 return QVariantList(); // empty list
918
919 // undefined - nothing makes sense here
920 case Sum:
921 case Min:
922 case Max:
923 case Mean:
924 case Median:
925 case StDev:
926 case StDevSample:
927 case Range:
928 case Minority:
929 case Majority:
930 case FirstQuartile:
931 case ThirdQuartile:
935 case GeometryCollect:
936 return QVariant();
937 }
938 return QVariant();
939}
940
941QVariant QgsAggregateCalculator::calculateDateTimeAggregate( QgsFeatureIterator &fit, int attr, QgsExpression *expression,
943{
944 Q_ASSERT( expression || attr >= 0 );
945
947 QgsFeature f;
948
949 while ( fit.nextFeature( f ) )
950 {
951 if ( expression )
952 {
953 Q_ASSERT( context );
954 context->setFeature( f );
955 const QVariant v = expression->evaluate( context );
956 s.addValue( v );
957 }
958 else
959 {
960 s.addValue( f.attribute( attr ) );
961 }
962 }
963 s.finalize();
964 return s.statistic( stat );
965}
966
967QVariant QgsAggregateCalculator::calculateArrayAggregate( QgsFeatureIterator &fit, int attr, QgsExpression *expression,
968 QgsExpressionContext *context )
969{
970 Q_ASSERT( expression || attr >= 0 );
971
972 QgsFeature f;
973
974 QVariantList array;
975
976 while ( fit.nextFeature( f ) )
977 {
978 if ( expression )
979 {
980 Q_ASSERT( context );
981 context->setFeature( f );
982 const QVariant v = expression->evaluate( context );
983 array.append( v );
984 }
985 else
986 {
987 array.append( f.attribute( attr ) );
988 }
989 }
990 return array;
991}
992
const QgsVectorLayer * layer() const
Returns the associated vector layer.
void setParameters(const AggregateParameters &parameters)
Sets all aggregate parameters from a parameter bundle.
void setFidsFilter(const QgsFeatureIds &fids)
Sets a filter to limit the features used during the aggregate calculation.
Aggregate
Available aggregates to calculate.
@ StringConcatenateUnique
Concatenate unique values with a joining string (string fields only). Specify the delimiter using set...
@ StDev
Standard deviation of values (numeric fields only)
@ StringMaximumLength
Maximum length of string (string fields only)
@ ThirdQuartile
Third quartile (numeric fields only)
@ Range
Range of values (max - min) (numeric and datetime fields only)
@ ArrayAggregate
Create an array of values.
@ InterQuartileRange
Inter quartile range (IQR) (numeric fields only)
@ FirstQuartile
First quartile (numeric fields only)
@ Median
Median of values (numeric fields only)
@ GeometryCollect
Create a multipart geometry from aggregated geometries.
@ CountMissing
Number of missing (null) values.
@ StDevSample
Sample standard deviation of values (numeric fields only)
@ Majority
Majority of values.
@ StringConcatenate
Concatenate values with a joining string (string fields only). Specify the delimiter using setDelimit...
@ Mean
Mean of values (numeric fields only)
@ StringMinimumLength
Minimum length of string (string fields only)
@ CountDistinct
Number of distinct values.
@ Minority
Minority of values.
static QList< QgsAggregateCalculator::AggregateInfo > aggregates()
Structured information for available aggregates.
QString delimiter() const
Returns the delimiter used for joining values with the StringConcatenate aggregate.
static Aggregate stringToAggregate(const QString &string, bool *ok=nullptr)
Converts a string to a aggregate type.
QVariant calculate(Aggregate aggregate, const QString &fieldOrExpression, QgsExpressionContext *context=nullptr, bool *ok=nullptr, QgsFeedback *feedback=nullptr) const
Calculates the value of an aggregate.
static QString displayName(Aggregate aggregate)
Returns the friendly display name for a aggregate.
QgsAggregateCalculator(const QgsVectorLayer *layer)
Constructor for QgsAggregateCalculator.
Calculator for summary statistics and aggregates for a list of datetimes.
Statistic
Enumeration of flags that specify statistics to be calculated.
@ Min
Minimum (earliest) datetime value.
@ Max
Maximum (latest) datetime value.
@ CountDistinct
Number of distinct datetime values.
@ Range
Interval between earliest and latest datetime value.
@ CountMissing
Number of missing (null) values.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsFeedback * feedback() const
Returns the feedback object that can be queried regularly by the expression to check if evaluation sh...
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
static std::tuple< QVariant::Type, int > determineResultType(const QString &expression, const QgsVectorLayer *layer, QgsFeatureRequest request=QgsFeatureRequest(), QgsExpressionContext context=QgsExpressionContext(), bool *foundFeatures=nullptr)
Returns a value type and user type for a given expression.
Class for parsing and evaluation of expressions (formerly called "search strings").
static int expressionToLayerFieldIndex(const QString &expression, const QgsVectorLayer *layer)
Attempts to resolve an expression to a field index from the given layer.
QVariant evaluate()
Evaluate the feature and return the result.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets the feature IDs that should be fetched.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
void setFeedback(QgsFeedback *feedback)
Attach a feedback object that can be queried regularly by the iterator to check if it should be cance...
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
QgsFeatureRequest & setOrderBy(const OrderBy &orderBy)
Set a list of order by clauses.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:338
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:45
QString name
Definition: qgsfield.h:61
QVariant::Type type
Definition: qgsfield.h:59
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:163
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:164
static QgsGeometry collectGeometry(const QVector< QgsGeometry > &geometries)
Creates a new multipart geometry from a list of QgsGeometry objects.
Calculator for summary statistics for a list of doubles.
Statistic
Enumeration of flags that specify statistics to be calculated.
@ InterQuartileRange
Inter quartile range (IQR)
@ Median
Median of values.
@ Variety
Variety (count of distinct) values.
@ Minority
Minority of values.
@ ThirdQuartile
Third quartile.
@ Majority
Majority of values.
@ CountMissing
Number of missing (null) values.
@ Range
Range of values (max - min)
@ StDevSample
Sample standard deviation of values.
@ FirstQuartile
First quartile.
@ StDev
Standard deviation of values.
Calculator for summary statistics and aggregates for a list of strings.
Statistic
Enumeration of flags that specify statistics to be calculated.
@ MaximumLength
Maximum length of string.
@ MinimumLength
Minimum length of string.
@ CountDistinct
Number of distinct string values.
@ CountMissing
Number of missing (null) values.
Represents a vector layer which manages a vector based data sets.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
const QString & typeName
Structured information about the available aggregates.
A bundle of parameters controlling aggregate calculation.
QString filter
Optional filter for calculating aggregate over a subset of features, or an empty string to use all fe...
QString delimiter
Delimiter to use for joining values with the StringConcatenate aggregate.
QgsFeatureRequest::OrderBy orderBy
Optional order by clauses.