Select to view content in your preferred language

UpdateCursor with nested loops and SelectLayerByAttributes

3019
3
04-30-2013 12:02 AM
MatthewBrown1
Deactivated User
Hi,

I need to update fields in a feature class based on values from another feature class (with different geometry). Some of the features have multiple values and are handled in a separate loop to the other values.

I have hacked something together that works with my test data, but using multiple SelectLayerByAttribute to get values from the other feature class makes it run much slower than I think it should. There must be a Python data structure I can use instead (like a dictionary with FID as key and LandCover as value) that will be faster and make my code more 'Pythonic'.

Any suggestions appreciated!

with arcpy.da.UpdateCursor(paddock, fields) as cursor:
    for row in cursor:
        #print row
        for i in singleList:
            #print i
            if row[0] == i[0]:
                arcpy.SelectLayerByAttribute_management(fc, "NEW_SELECTION", """"FID" = {0}""".format(i[0]))
                landCover = list(r.LandCover for r in arcpy.SearchCursor(fc))
                #print "updating.... " + landCover[0]
                row[1] = landCover[0]
                cursor.updateRow(row)
        for i in dupList:
            #print i
            if row[0] == i[0]:
                arcpy.SelectLayerByAttribute_management(fc, "NEW_SELECTION", """"FID" = {0}""".format(i[0]))
                landcoverList = list((r.LandCover,r.Shape_Area) for r in arcpy.SearchCursor(fc))
                maxlandCover = max(landcoverList, key=lambda x: x[1])
                landCover = list(maxlandCover)[0]
                #print "updating.... " + landCover
                row[1] = landCover
                cursor.updateRow(row)


Thanks,

Matt
Tags (2)
0 Kudos
3 Replies
MathewCoyle
Honored Contributor
First off cursors can be created with a query so selecting by attributes to run a cursor on the selection is 100% redundant. How big are your singleList and dupList variables? Those seem like where the biggest bottleneck using your code would be.
0 Kudos
ArkadiuszMatoszka
Frequent Contributor
Hi,
There are two bottlenecks in your code. You pointed out first which is calling arcpy.SelectLayerByAttribute_management multiple times, other is creating new arcpy.SearchCursor(fc) object for each matched FID.
Your idea with dict is good. Below is code with more generic solution, which iterates through feature class and creates dictonary where key is FID and value is another dictionary that maps fieldname to its value for each row.

fields = [f.name for f in arcpy.ListFields(fc) if f.name.upper() not in ('FID', 'SHAPE')]
collector = arcpy.SearchCursor(fc)
data = {}
for feature in collector:
    data[feature.FID] = {f: feature.getValue(f) for f in fields}
del collector


Getting LandCover field value from this would be:
LandCover = data[i[0]]['LandCover']


You can simplify this to get only LandCover value - in this case I would suggest using arcpy.da.SearchCursor instead of arcpy.SearchCursor because of its efficiency. So it would be something like:
data = {}
with arcpy.da.SearchCursor(fc, ['FID', 'LandCover']) as collector:
  for row in collector:
    data[row[0]] = row[1]

Then getting value of LandCover field would be:
LandCover = data[i[0]]


Hope it help.
Regards
Arek
0 Kudos
MatthewBrown1
Deactivated User

fields = [f.name for f in arcpy.ListFields(fc) if f.name.upper() not in ('FID', 'SHAPE')]
collector = arcpy.SearchCursor(fc)
data = {}
for feature in collector:
    data[feature.FID] = {f: feature.getValue(f) for f in fields}
del collector



Hi Arek,

Looks like getValue() was a major piece of the puzzle that I was missing!

I will try to implement this later and post back.

Thanks,

Matt
0 Kudos