I'm building my first script and I need help to create a loop instead of my repetitiv functions. The aim is to check if every field already exists, and to build it only if it doesn't.
This script does what I want:
layer = iface.activeLayer()
dpr = layer.dataProvider()
if layer.fields().indexFromName("apr") == -1:
dpr.addAttributes([QgsField("apr", QVariant.String)])
if layer.fields().indexFromName("iso") == -1:
dpr.addAttributes([QgsField("iso", QVariant.String)])
if layer.fields().indexFromName("exp") == -1:
dpr.addAttributes([QgsField("exp", QVariant.String)])
if layer.fields().indexFromName("foca") == -1:
dpr.addAttributes([QgsField("foca", QVariant.String)])
if layer.fields().indexFromName("foca35") == -1:
dpr.addAttributes([QgsField("foca35", QVariant.Double)])
if layer.fields().indexFromName("shsp") == -1:
dpr.addAttributes([QgsField("shsp", QVariant.Double)])
if layer.fields().indexFromName("fyd") == -1:
dpr.addAttributes([QgsField("fyd", QVariant.Double)])
if layer.fields().indexFromName("gyd") == -1:
dpr.addAttributes([QgsField("gyd", QVariant.Double)])
if layer.fields().indexFromName("ra") == -1:
dpr.addAttributes([QgsField("ra", QVariant.Double)])
if layer.fields().indexFromName("pi") == -1:
dpr.addAttributes([QgsField("pi", QVariant.Double)])
Here's my first attempt to convert it into a loop. This code doesn't work because of synthax, probably this partQVariant.fields_arr[i][1]
Also, I would like to know if there is another way to optimize it? The loop's action performs addAttributes every time. Could not we optimize that by using addAttributes function only one time after the loop?
layer = iface.activeLayer()
dpr = layer.dataProvider()
fields_arr = [["apr", "Double"],
["iso", "Double"],
["exp", "String"],
["foca", "Double"],
["foca35", "Double"],
["shsp", "Double"],
["fyd", "Double"],
["gyd", "Double"],
["ra", "Double"],
["pi", "Double"]]
for i in range(0,9):
if layer.fields().indexFromName(fields_arr[i][0]) == -1:
dpr.addAttributes([QgsField(fields_arr[i][0], QVariant.fields_arr[i][1])])
1 Answer 1
If you change the data structure of your fields array slightly, the following should work:
layer = iface.activeLayer()
fields_arr = [("apr", QVariant.Double),
("iso", QVariant.Double),
("exp", QVariant.String),
("foca", QVariant.Double),
("foca35", QVariant.Double),
("shsp", QVariant.Double),
("fyd", QVariant.Double),
("gyd", QVariant.Double),
("ra", QVariant.Double),
("pi", QVariant.Double)]
for i in fields_arr:
if i[0] not in [fld.name() for fld in layer.fields()]:
layer.dataProvider().addAttributes([QgsField(i[0], i[1])])
layer.updateFields()
As for optimization, yes- you could call addAttributes()
at the end and pass all fields together in a list.
You could achieve this by creating a list of fields using a list comprehension like:
flds = [QgsField(i[0], i[1]) for i in fields_arr if i[0] not in [fld.name() for fld in layer.fields()]]
layer.dataProvider().addAttributes(flds)
layer.updateFields()
For the number of fields you are adding, I can't imagine this would result in any noticeable difference in performance.
create a dummyvariable and set it to 0. while [dummyvariable] < [number of times to perform the loop], do [action], [add 1 to dummyvariable]
. In your case the action isif layer.fields().indexFromName(fieldname) == -1: dpr.addAttributes([QgsField(fieldname, QVariant.String)])
. Create an array of all the fieldname values, and use an array function to get the array item at the array position of your dummy variable. That way each time the loop runs the action, it uses the next fieldname in the list.