4

enter image description here

I am having an attribute table information for line features. Each Line feature has LINK ID's which are supposed to be unique but in some places are repeating. Also I have a field "NEW" whose Id's are completely unique.

Now I want to obtain "New" Id values of those features which are having same Link ID value, and based on the length of those features (if among them the feature having highest length will have its LINK ID unchanged) and the others will be changed to 0 (Link Id).

So my plan was to create a dictionary with Link ID as key, - dict['LinkId'] = [1 , [2]]

Here 1 represents a list of New Id's and 2 represents list of lengths of the line features. Here 1 and 2 item should be synchronous for e.g- { 714882134 : [0: 1823048.3948], [23 : 485879.84]}

so from that of 2 which ever is having the highest value I will obtain its corresponding new id.

Here is the code I have written but it is not exactly returning the thing I want.

    vlayer.startEditing()
    ids = []
    for feature in vlayer.getFeatures():
        id = feature['LINK_ID']
        if id not in ids and id != 0:
            ids.append(id)
        else:
           pass
    vlayer.commitChanges()

    dict = {}
    vlayer.startEditing()
    for feature in vlayer.getFeatures():
        geom = feature.geometry()
        length = round(geom.length(),8)
        link_id = feature['LINK_ID']
        cat = int(feature['NEW'])
        for data in ids:
            if data == link_id:
                dict[link_id] = [(length),(cat)]
    vlayer.commitChanges()

    print("dict")
    print(dict)

I am using QGIS version 3.16.3

2
  • Based on the implementation provided, it seems to me that repeated link_id will overwrite each other in dict. So maybe you can use a dict = defaultdict(list) and append the values (e.g., dict[link_id].append((length), (cat)) when you find repeating link_id. It can be a suggestion for the start.
    – fastest
    Commented Mar 10, 2022 at 16:02
  • hi @fastest the name default dict is not recignized I get this error- dict = defaultdict(list) NameError: name 'defaultdict' is not defined Commented Mar 11, 2022 at 5:24

1 Answer 1

4

I like to use collections defaultdict list for problems like this. (Your problem can be solved using a simple dictionary if you dont need to list the duplicates, just set one of them to 0.)

from collections import defaultdict
layer = QgsProject.instance().mapLayersByName('scratch')[0]

#Create the defaultdict and add values to it
d = defaultdict(list)
for f in layer.getFeatures():
    d[f['LINK_ID']].append(f)
   
#Now, for each key/LINK_ID there's a list of all features with that LINK_ID
#defaultdict(<class 'list'>, 
#{12345: [<qgis._core.QgsFeature object at 0x7fe91c04fee0>], 
 #11111: [<qgis._core.QgsFeature object at 0x7fe91c04fa60>, qgis._core.QgsFeature object at 0x7fea6a5ae160>], 
 #222: [<qgis._core.QgsFeature object at 0x7fea6a5ae4c0>, <qgis._core.QgsFeature object at 0x7fea6a5ae3a0>]})    

dups = [v for k,v in d.items() if len(v)>1] #Drop the LINK_ID's which have only 1 value

print([[f['NEW'] for f in sublist] for sublist in dups])
#[[4, 5], [2, 3]]

dups = [sorted(sublist, key=lambda x: x.geometry().length()) for sublist in dups] #Sort by geometry length

print([[f['NEW'] for f in sublist] for sublist in dups])
#[[4, 5], [3, 2]] So 4 and 3 are shortest in their LINK_ID groups

to_update = [sublist[0] for sublist in dups]
#[<qgis._core.QgsFeature object at 0x7fe91c1208b0>, <qgis._core.QgsFeature object at 0x7fea6a5ae670>]
LINK_ID_index = layer.fields().indexFromName('LINK_ID')
new_attributes = {feature.id():{LINK_ID_index:0} for feature in to_update}
#{3: {1: 0}, 4: {1: 0}} #So feature with id 3, should in field with index 1 get a zero, ...
layer.dataProvider().changeAttributeValues(new_attributes) #Update the values

enter image description here

Your Answer

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

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