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?

Taras
  • 32,823
  • 4
  • 66
  • 137
i.i.k.
  • 1,427
  • 5
  • 11
  • I'm confused: Why was my code 'edited' without being changed in any way? – i.i.k. Jun 10 '23 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. – Rohit Gupta Jun 14 '23 at 13:26

2 Answers2

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

BERA
  • 72,339
  • 13
  • 72
  • 161
  • 1
    Oh, this looks very nice, kind of elegant! Thank you very much, I will try it! – i.i.k. Jun 09 '23 at 09: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 '23 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 '23 at 06: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:

Taras
  • 32,823
  • 4
  • 66
  • 137