4

I have two fields which I want to merge into a single field, thereby should one of the two to-be-merged fields be prioritized, meaning, if a value of one field is available take it instead of the other field.

I would like to have it like this:

field1 | field2 | resultField
-----------------------------
13     | NULL   | 13
28     | 56     | 56
44     | NULL   | 44
11     | 17     | 17

So the "field2" should be prioritized in the resulting field.

I know, that I will need to create a new field, with the name relevant field name, so

vectorLyr =  QgsVectorLayer('path_to_filed', 'layername', "ogr")
vectorLyr.isValid()

vpr = vectorLyr.dataProvider()

fieldnames = [resultField]

for name in fieldnames:
    vpr.addAttributes([QgsField(name, QVariant.Double)])
    vectorLyr.updateFields()

However, how can I now update the "resultfield" with the values from the two fields?

2
  • I'm confused: Why was my code 'edited' without being changed in any way?
    – i.i.k.
    Jun 10 at 22:35
  • Editing is a normal part of these sites. In the above case, the tag pyqgis was added to the backticks to tell it how to colourize it. Jun 14 at 13:26

2 Answers 2

7

You can use or like this, i think it is called Ternary operators:

layer = iface.activeLayer()
p = layer.dataProvider()
field_to_update = "field3"
fieldindex = layer.fields().indexOf(field_to_update)

attributemap = {} #A dictionary to store {feature id: {index of field to update : new value}}
for f in layer.getFeatures(): #For each feature
    f1, f2 = f["field1"], f["field2"] #Extract the values in field1 and field2
    attributemap[f.id()] = {fieldindex: f2 or f1 or -999} #Take the first not null value, or if there is none, use -999

#attributemap[1]
#{4: 83} Feature 1 should in field 4 get the value 83

p.changeAttributeValues(attributemap)

enter image description here

3
  • 1
    Oh, this looks very nice, kind of elegant! Thank you very much, I will try it!
    – i.i.k.
    Jun 9 at 9:25
  • I adjusted my code accordingly and ran into a little problem: Python interpretes the value 0 as NULL, so that all values which are 0 or NULL become -999. However, 0 is 0 and not 'None'. Any idea how to tackle this problem?
    – i.i.k.
    Jun 11 at 17:32
  • Oh. Try replacing f2 or f1 or -999 with next(item for item in [f2, f1, -999] if item is not None)
    – BERA
    Jun 12 at 6:49
1

Another approach might be not as Pythonic as was suggested by @BERA, however, it is still applicable in terms of PyQGIS.

It utilizes the coalesce() function inside the QgsExpression() class.

Proceed with Plugins > Python Console > Show Editor and paste the script below

from qgis.core import QgsProject, QgsExpression, QgsExpressionContext, QgsExpressionContextUtils

# refer to a layer by its name
layer = QgsProject.instance().mapLayersByName("lines")[0]

# set up an expression including two desired fields
expression = QgsExpression('coalesce("field1", "field2")')

# define the expression context to encapsulate parameters for evaluation
context = QgsExpressionContext()
context.appendScopes(QgsExpressionContextUtils.globalProjectLayerScopes(layer))

# start layer editing
with edit(layer):
    for feat in layer.getFeatures():
        context.setFeature(feat)
        feat["result"] = expression.evaluate(context)
        layer.updateFeature(feat)

Press Run script run script and get the output that will look like:

result

P.S. To achieve -999 where "field1" and "field2" are both NULLs, please modify the expression accordingly:

expression = QgsExpression('coalesce("field1", "field2", -999)')

References:

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.