Skip to content

Commit

Permalink
[processing] Optimise uniqueValues method
Browse files Browse the repository at this point in the history
Now it uses the standard QgsVectorLayer.uniqueValues() method
where possible so that provider side optimisations are used

Also add test, and optimise request when using selected
features only
  • Loading branch information
nyalldawson committed Oct 12, 2016
1 parent 05ea4be commit 6605a22
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 6 deletions.
26 changes: 26 additions & 0 deletions python/plugins/processing/tests/ToolsTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,32 @@ def testValues(self):

ProcessingConfig.setSettingValue(ProcessingConfig.USE_SELECTED, previous_value)

def testUniqueValues(self):
ProcessingConfig.initialize()

test_data = points2()
test_layer = QgsVectorLayer(test_data, 'test', 'ogr')

# field by index
v = vector.uniqueValues(test_layer, 3)
self.assertEqual(len(v), len(set(v)))
self.assertEqual(set(v), set([2, 1, 0]))

# field by name
v = vector.uniqueValues(test_layer, 'id_2')
self.assertEqual(len(v), len(set(v)))
self.assertEqual(set(v), set([2, 1, 0]))

# test with selected features
previous_value = ProcessingConfig.getSetting(ProcessingConfig.USE_SELECTED)
ProcessingConfig.setSettingValue(ProcessingConfig.USE_SELECTED, True)
test_layer.selectByIds([2, 4, 6])
v = vector.uniqueValues(test_layer, 'id')
self.assertEqual(len(v), len(set(v)))
self.assertEqual(set(v), set([5, 7, 3]))

ProcessingConfig.setSettingValue(ProcessingConfig.USE_SELECTED, previous_value)


if __name__ == '__main__':
unittest.main()
22 changes: 16 additions & 6 deletions python/plugins/processing/tools/vector.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,23 @@ def uniqueValues(layer, attribute):
Attribute can be defined using a field names or a zero-based
field index. It considers the existing selection.
"""
values = []

fieldIndex = resolveFieldIndex(layer, attribute)
feats = features(layer)
for feat in feats:
if feat.attributes()[fieldIndex] not in values:
values.append(feat.attributes()[fieldIndex])
return values
if ProcessingConfig.getSetting(ProcessingConfig.USE_SELECTED) \
and layer.selectedFeatureCount() > 0:

# iterate through selected features
values = []
request = QgsFeatureRequest().setSubsetOfAttributes([fieldIndex]).setFlags(QgsFeatureRequest.NoGeometry)
feats = features(layer, request)
for feat in feats:
if feat.attributes()[fieldIndex] not in values:
values.append(feat.attributes()[fieldIndex])
return values
else:
# no selection, or not considering selecting
# so we can take advantage of provider side unique value optimisations
return layer.uniqueValues(fieldIndex)


def resolveFieldIndex(layer, attr):
Expand Down

0 comments on commit 6605a22

Please sign in to comment.