Skip to content

Commit

Permalink
[processing] Fix inefficient values() method
Browse files Browse the repository at this point in the history
Method was iterating over ever feature in a layer, including
geometries and all attributes for EVERY attribute requested

Add test and refactor so only one optimised iteration (eg no
geometry, only required attributes) is used
  • Loading branch information
nyalldawson committed Oct 12, 2016
1 parent 2665eb5 commit 05ea4be
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 7 deletions.
38 changes: 38 additions & 0 deletions python/plugins/processing/tests/ToolsTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,44 @@ def testFeatures(self):

ProcessingConfig.setSettingValue(ProcessingConfig.USE_SELECTED, previous_value)

def testValues(self):
ProcessingConfig.initialize()

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

# field by index
res = vector.values(test_layer, 0)
self.assertEqual(res[0], [1, 2, 3, 4, 5, 6, 7, 8])

# field by name
res = vector.values(test_layer, 'id')
self.assertEqual(res['id'], [1, 2, 3, 4, 5, 6, 7, 8])

# two fields
res = vector.values(test_layer, 0, 3)
self.assertEqual(res[0], [1, 2, 3, 4, 5, 6, 7, 8])
self.assertEqual(res[3], [2, 1, 0, 2, 1, 0, 0, 0])

# two fields by name
res = vector.values(test_layer, 'id', 'id_2')
self.assertEqual(res['id'], [1, 2, 3, 4, 5, 6, 7, 8])
self.assertEqual(res['id_2'], [2, 1, 0, 2, 1, 0, 0, 0])

# two fields by name and index
res = vector.values(test_layer, 'id', 3)
self.assertEqual(res['id'], [1, 2, 3, 4, 5, 6, 7, 8])
self.assertEqual(res[3], [2, 1, 0, 2, 1, 0, 0, 0])

# test with selected features
previous_value = ProcessingConfig.getSetting(ProcessingConfig.USE_SELECTED)
ProcessingConfig.setSettingValue(ProcessingConfig.USE_SELECTED, True)
test_layer.selectByIds([2, 4, 6])
res = vector.values(test_layer, 0)
self.assertEqual(set(res[0]), set([5, 7, 3]))

ProcessingConfig.setSettingValue(ProcessingConfig.USE_SELECTED, previous_value)


if __name__ == '__main__':
unittest.main()
27 changes: 20 additions & 7 deletions python/plugins/processing/tools/vector.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,17 +163,30 @@ def values(layer, *attributes):
to a number.
"""
ret = {}
indices = []
attr_keys = {}
for attr in attributes:
index = resolveFieldIndex(layer, attr)
values = []
feats = features(layer)
for feature in feats:
indices.append(index)
attr_keys[index] = attr

# use an optimised feature request
request = QgsFeatureRequest().setSubsetOfAttributes(indices).setFlags(QgsFeatureRequest.NoGeometry)

for feature in features(layer, request):
for i in indices:

# convert attribute value to number
try:
v = float(feature.attributes()[index])
values.append(v)
v = float(feature.attributes()[i])
except:
values.append(None)
ret[attr] = values
v = None

k = attr_keys[i]
if k in ret:
ret[k].append(v)
else:
ret[k] = [v]
return ret


Expand Down

1 comment on commit 05ea4be

@nirvn
Copy link
Contributor

@nirvn nirvn commented on 05ea4be Oct 12, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yay.

Please sign in to comment.