[GIS] Selecting rows in a layer using arcpy.SearchCursor

arcgis-10.3arcpycursorselect-by-location

I'm working on a project to identify points that fall along lengths of road. The roads are stored a single featureclass within a file geodatabase, as are the points. I'm using ArcGIS 10.3.

I'm trying to use an arcpy search cursor, configured with a for statement to iterate through my roads dataset. Within the for loop I'm using the function row.getValue to return a 3 digit short integer stored within a field called 'FacilityID' within the attributes of the roads layer. I wish to then use this value to select the appropriate row within the roads layer. Further down the line I would then use this selected row as the basis of a select by location query. At the moment my code doesn't iterate through selections. I can get it to print all the 3 digit integers within the 'FacilityID' field, but it ceases to work if I use the arcpy.SelectLayerByAttribute_management tool.

As I feel I'm not explaining all of this very well, I will include a cut down version of my code:

import arcpy, os
from arcpy import env
arcpy.env.workspace = "C:\Temp\Test.gdb"

env.overwriteOutput = True

ROADS = "Test_Roads"

FIELD = "FacilityID"

roadcursor = arcpy.SearchCursor(roads_lyr)

for row in roadcursor:
    ROADID = (row.getValue(FIELD))
    print ROADID, type(ROADID)

    expression1 = "\"FacilityID\" = " + str(ROADID)
    arcpy.SelectLayerByAttribute_management(roads_lyr, "NEW_SELECTION", expression1)

    arcpy.SelectLayerByAttribute_management(roads_lyr, "REMOVE_FROM_SELECTION", expression1)

I've changed the selection type to 'clear selection' in the second, and get the same result.

Best Answer

My preferred method for iterating through records and selecting each one is as follows. Kind of long winded here, but all the functions are very useful for this kind of thing.

import arcpy, os

# Create a script tool
roadFeatures = arcpy.GetParameterAsText(0)
field = arcpy.GetParameterAsText(0)  #in the tool setup, use the "obtain from" setting and set it to the road features

#Or, just assign your data, as you did previously
#
#roadFeatures = "Test_Roads"
#field = "FacilityID"

## I use these 3 functions all the time, very handy ##

def getFieldList(fc):  #return list of strings for field names
    fieldObjects = arcpy.ListFields(fc)
    fieldList = []
    for field in fieldObjects:
        fieldList.append(field.name)
    return fieldList

def createWhereClause(table, field, valueList):  #builds a where clause so you dont have to!                     
    fieldDelimited = arcpy.AddFieldDelimiters(arcpy.Describe(table).path, field) 
    fieldType = arcpy.ListFields(table, field)[0].type                            
    if str(fieldType) == 'String':                                                
        valueList = ["'%s'" % value for value in valueList]                             
    whereClause = "%s IN(%s)" % (fieldDelimited, ', '.join(map(str, valueList)))        
    return whereClause

def returnFieldIndex(inFC, fieldName):  #returns int index of specified field
    fieldList = getFieldList(inFC)
    index = 0
    try:
        for fld in fieldList:
            if fieldName == fld:
                return int(index)
                index += 1
            else:
                index += 1
    except:
        arcpy.AddMessage("Error in returning field index.")

################################################################


fieldList = getFieldList(roadFeatures)

fieldIndex = returnFieldIndex(roadFeatures, field)

arcpy.MakeFeatureLayer(roadFeatures, "roadsLayer")

with arcpy.da.SearchCursor("roadsLayer", (fieldList)) as cursor:
    for row in cursor:
        #This line creates a where clause that basically says, "make a clause for the row with the object ID
        #that I am currently iterating".
        whereClause = createWhereClause("roadsLayer", field, [row[fieldIndex]])
        arcpy.SelectLayerByAttribute_management("roadsLayer", "CLEAR_SELECTION")
        arcpy.SelectLayerByAttribute_management("roadsLayer", "NEW_SELECTION", whereClause)
        #Now perform all of the other code you need on the "roadsLayer" which will have the current row selected.

The script works by selecting each row based on the "field" index.

Psuedo: for each row in the dataset get the "field" value and then select the row with the field value (aka, the current row)

Note: If you are assigning a layer to the roadFeatures object, you will not need the MakeFeatureLayer line.

Related Question