Skip to content

Commit 5f817b4

Browse files
committed
Allow QgsStatisticalSummary to calculate first/last value
Trivial, but simplifies other code which desires to expose a choice between first/last/min/max/mean/etc...
1 parent 5586352 commit 5f817b4

File tree

4 files changed

+83
-18
lines changed

4 files changed

+83
-18
lines changed

python/core/auto_generated/qgsstatisticalsummary.sip.in

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ specifying the statistic in the constructor or via setStatistics().
4646
FirstQuartile,
4747
ThirdQuartile,
4848
InterQuartileRange,
49+
First,
50+
Last,
4951
All
5052
};
5153
typedef QFlags<QgsStatisticalSummary::Statistic> Statistics;
@@ -214,6 +216,24 @@ be calculated.
214216
%Docstring
215217
Returns calculated range (difference between maximum and minimum values). A NaN value may be returned if the range cannot
216218
be calculated.
219+
%End
220+
221+
double first() const;
222+
%Docstring
223+
Returns the first value obtained. A NaN value may be returned if no values were encountered.
224+
225+
.. seealso:: :py:func:`last`
226+
227+
.. versionadded:: 3.6
228+
%End
229+
230+
double last() const;
231+
%Docstring
232+
Returns the last value obtained. A NaN value may be returned if no values were encountered.
233+
234+
.. seealso:: :py:func:`first`
235+
236+
.. versionadded:: 3.6
217237
%End
218238

219239
double stDev() const;

src/core/qgsstatisticalsummary.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ QgsStatisticalSummary::QgsStatisticalSummary( Statistics stats )
3232

3333
void QgsStatisticalSummary::reset()
3434
{
35+
mFirst = std::numeric_limits<double>::quiet_NaN();
36+
mLast = std::numeric_limits<double>::quiet_NaN();
3537
mCount = 0;
3638
mMissing = 0;
3739
mSum = 0;
@@ -59,7 +61,7 @@ void QgsStatisticalSummary::calculate( const QList<double> &values )
5961
{
6062
reset();
6163

62-
Q_FOREACH ( double value, values )
64+
for ( double value : values )
6365
{
6466
addValue( value );
6567
}
@@ -69,10 +71,13 @@ void QgsStatisticalSummary::calculate( const QList<double> &values )
6971

7072
void QgsStatisticalSummary::addValue( double value )
7173
{
74+
if ( mCount == 0 )
75+
mFirst = value;
7276
mCount++;
7377
mSum += value;
7478
mMin = std::min( mMin, value );
7579
mMax = std::max( mMax, value );
80+
mLast = value;
7681

7782
if ( mStatistics & QgsStatisticalSummary::Majority || mStatistics & QgsStatisticalSummary::Minority || mStatistics & QgsStatisticalSummary::Variety )
7883
mValueCount.insert( value, mValueCount.value( value, 0 ) + 1 );
@@ -102,6 +107,8 @@ void QgsStatisticalSummary::finalize()
102107
{
103108
if ( mCount == 0 )
104109
{
110+
mFirst = std::numeric_limits<double>::quiet_NaN();
111+
mLast = std::numeric_limits<double>::quiet_NaN();
105112
mMin = std::numeric_limits<double>::quiet_NaN();
106113
mMax = std::numeric_limits<double>::quiet_NaN();
107114
mMean = std::numeric_limits<double>::quiet_NaN();
@@ -266,6 +273,10 @@ double QgsStatisticalSummary::statistic( QgsStatisticalSummary::Statistic stat )
266273
return mThirdQuartile;
267274
case InterQuartileRange:
268275
return mThirdQuartile - mFirstQuartile;
276+
case First:
277+
return mFirst;
278+
case Last:
279+
return mLast;
269280
case All:
270281
return 0;
271282
}
@@ -308,6 +319,10 @@ QString QgsStatisticalSummary::displayName( QgsStatisticalSummary::Statistic sta
308319
return QObject::tr( "Q3" );
309320
case InterQuartileRange:
310321
return QObject::tr( "IQR" );
322+
case First:
323+
return QObject::tr( "First" );
324+
case Last:
325+
return QObject::tr( "Last" );
311326
case All:
312327
return QString();
313328
}

src/core/qgsstatisticalsummary.h

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -47,23 +47,25 @@ class CORE_EXPORT QgsStatisticalSummary
4747
//! Enumeration of flags that specify statistics to be calculated
4848
enum Statistic
4949
{
50-
Count = 1, //!< Count
51-
CountMissing = 32770, //!< Number of missing (null) values
52-
Sum = 2, //!< Sum of values
53-
Mean = 4, //!< Mean of values
54-
Median = 8, //!< Median of values
55-
StDev = 16, //!< Standard deviation of values
56-
StDevSample = 32, //!< Sample standard deviation of values
57-
Min = 64, //!< Min of values
58-
Max = 128, //!< Max of values
59-
Range = 256, //!< Range of values (max - min)
60-
Minority = 512, //!< Minority of values
61-
Majority = 1024, //!< Majority of values
62-
Variety = 2048, //!< Variety (count of distinct) values
63-
FirstQuartile = 4096, //!< First quartile
64-
ThirdQuartile = 8192, //!< Third quartile
65-
InterQuartileRange = 16384, //!< Inter quartile range (IQR)
66-
All = Count | CountMissing | Sum | Mean | Median | StDev | Max | Min | Range | Minority | Majority | Variety | FirstQuartile | ThirdQuartile | InterQuartileRange
50+
Count = 1 << 0, //!< Count
51+
CountMissing = 1 << 15, //!< Number of missing (null) values
52+
Sum = 1 << 1, //!< Sum of values
53+
Mean = 1 << 2, //!< Mean of values
54+
Median = 1 << 3, //!< Median of values
55+
StDev = 1 << 4, //!< Standard deviation of values
56+
StDevSample = 1 << 5, //!< Sample standard deviation of values
57+
Min = 1 << 6, //!< Min of values
58+
Max = 1 << 7, //!< Max of values
59+
Range = 1 << 8, //!< Range of values (max - min)
60+
Minority = 1 << 9, //!< Minority of values
61+
Majority = 1 << 10, //!< Majority of values
62+
Variety = 1 << 11, //!< Variety (count of distinct) values
63+
FirstQuartile = 1 << 12, //!< First quartile
64+
ThirdQuartile = 1 << 13, //!< Third quartile
65+
InterQuartileRange = 1 << 14, //!< Inter quartile range (IQR)
66+
First = 1 << 16, //!< First value (since QGIS 3.6)
67+
Last = 1 << 17, //!< Last value (since QGIS 3.6)
68+
All = Count | CountMissing | Sum | Mean | Median | StDev | Max | Min | Range | Minority | Majority | Variety | FirstQuartile | ThirdQuartile | InterQuartileRange | First | Last
6769
};
6870
Q_DECLARE_FLAGS( Statistics, Statistic )
6971

@@ -199,6 +201,22 @@ class CORE_EXPORT QgsStatisticalSummary
199201
*/
200202
double range() const { return std::isnan( mMax ) || std::isnan( mMin ) ? std::numeric_limits<double>::quiet_NaN() : mMax - mMin; }
201203

204+
/**
205+
* Returns the first value obtained. A NaN value may be returned if no values were encountered.
206+
*
207+
* \see last()
208+
* \since QGIS 3.6
209+
*/
210+
double first() const { return mFirst; }
211+
212+
/**
213+
* Returns the last value obtained. A NaN value may be returned if no values were encountered.
214+
*
215+
* \see first()
216+
* \since QGIS 3.6
217+
*/
218+
double last() const { return mLast; }
219+
202220
/**
203221
* Returns population standard deviation. This is only calculated if Statistic::StDev has
204222
* been specified in the constructor or via setStatistics. A NaN value may be returned if the standard deviation cannot
@@ -290,6 +308,8 @@ class CORE_EXPORT QgsStatisticalSummary
290308
double mMajority;
291309
double mFirstQuartile;
292310
double mThirdQuartile;
311+
double mFirst;
312+
double mLast;
293313
QMap< double, int > mValueCount;
294314
QList< double > mValues;
295315
};

tests/src/core/testqgsstatisticalsummary.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ void TestQgsStatisticSummary::stats()
8585
QCOMPARE( s2.sum(), 24.0 );
8686
QCOMPARE( s.mean(), 4.0 );
8787
QCOMPARE( s2.mean(), 4.0 );
88+
QCOMPARE( s.first(), 4.0 );
89+
QCOMPARE( s2.first(), 4.0 );
90+
QCOMPARE( s.last(), 8.0 );
91+
QCOMPARE( s2.last(), 8.0 );
8892
QGSCOMPARENEAR( s.stDev(), 2.0816, 0.0001 );
8993
QGSCOMPARENEAR( s2.stDev(), 2.0816, 0.0001 );
9094
QGSCOMPARENEAR( s.sampleStDev(), 2.2803, 0.0001 );
@@ -227,6 +231,8 @@ void TestQgsStatisticSummary::individualStatCalculations_data()
227231
QTest::newRow( "third_quartile" ) << ( int )QgsStatisticalSummary::ThirdQuartile << 5.0;
228232
QTest::newRow( "iqr" ) << ( int )QgsStatisticalSummary::InterQuartileRange << 2.0;
229233
QTest::newRow( "missing" ) << ( int )QgsStatisticalSummary::CountMissing << 0.0;
234+
QTest::newRow( "first" ) << static_cast< int >( QgsStatisticalSummary::First ) << 4.0;
235+
QTest::newRow( "last" ) << static_cast< int >( QgsStatisticalSummary::Last ) << 8.0;
230236
}
231237

232238
void TestQgsStatisticSummary::individualStatCalculations()
@@ -311,6 +317,10 @@ void TestQgsStatisticSummary::noValues()
311317
QCOMPARE( s.statistic( QgsStatisticalSummary::CountMissing ), 0.0 );
312318
QCOMPARE( s.sum(), 0.0 );
313319
QCOMPARE( s.statistic( QgsStatisticalSummary::Sum ), 0.0 );
320+
QVERIFY( std::isnan( s.first() ) );
321+
QVERIFY( std::isnan( s.statistic( QgsStatisticalSummary::First ) ) );
322+
QVERIFY( std::isnan( s.last() ) );
323+
QVERIFY( std::isnan( s.statistic( QgsStatisticalSummary::Last ) ) );
314324
QVERIFY( std::isnan( s.mean() ) );
315325
QVERIFY( std::isnan( s.statistic( QgsStatisticalSummary::Mean ) ) );
316326
QVERIFY( std::isnan( s.median() ) );

0 commit comments

Comments
 (0)