def factorial( number ): if number <= 1: return 1 else: return number * factorial( number - 1 )
a recursive function is one that calls itself, not one that loops per se
import sys, string, os, arcpy inLayer = arcpy.GetParameterAsText(0) #input layer clusterIdField = arcpy.GetParameterAsText(1) #the name of the 'CLUSTER_ID' field that will be added to inLayer selectionMethod = arcpy.GetParameterAsText(2) #the selectbylocation method (such as WITHIN_A_DISTANCE or INTERSECT) distThreshold = arcpy.GetParameterAsText(3) #A distance threashold if using the WITHIN_A_DISTANCE selection method selectionBuffer = arcpy.GetParameterAsText(4) #A max number of features to be selected set at once... performace gets slow if selection gets too big if selectionBuffer in ("","#",None): selectionBuffer = 500 if int(selectionBuffer) < 1: selectionBuffer = 500 fieldList = arcpy.ListFields(inLayer, clusterIdField) if fieldList == []: arcpy.AddField_management(inLayer, clusterIdField, "LONG") else: if fieldList[0].type not in ["SmallInteger","Integer","Double","Float"]: arcpy.AddError("ERROR: Existing " + str(clusterIdField) + " field type must be a numeric type (not a type of " + str(fieldList[0].type) + "! Exiting script..."); sys.exit(1) oidFieldName = arcpy.Describe(inLayer).oidFieldName arcpy.AddMessage("Cataloging " + str(oidFieldName) + " values...") oidDict = {} for r in arcpy.da.SearchCursor(inLayer, ["OID@"]): oidDict[r[0]] = -1 featureCount = len(oidDict) if featureCount == 0: arcpy.AddError("ERROR: Could not find any features to identify! Exiting script...");sys.exit(1) arcpy.AddMessage("Looking for clusters...") identifiedFeatures = 0 clusterId = 0 arcpy.MakeFeatureLayer_management(inLayer, "fl1", "") #Test to see if this helps clear the memory leak arcpy.SetProgressor("step", "Progress", 0, 100, 1) pctDone = 0 while identifiedFeatures < featureCount: clusterId = clusterId + 1 try: nextOidSeedValue = (key for key,value in oidDict.items() if value == -1).next() except: break arcpy.SelectLayerByAttribute_management("fl1", "NEW_SELECTION", oidFieldName + " = " + str(nextOidSeedValue)) globalPreSelectionOidSet = set() globalPostSelectionOidSet = set([nextOidSeedValue]) loopCount = 0 #for fun bufferReductionCount = 0 #for fun while len(globalPostSelectionOidSet) > len(globalPreSelectionOidSet): loopCount = loopCount + 1 preSelectionOidSet = set([r[0] for r in arcpy.da.SearchCursor("fl1", ["OID@"])]) globalPreSelectionOidSet = globalPreSelectionOidSet.union(preSelectionOidSet) arcpy.SelectLayerByLocation_management("fl1", selectionMethod, "fl1", distThreshold, "NEW_SELECTION") postSelectionOidSet = set([r[0] for r in arcpy.da.SearchCursor("fl1", ["OID@"])]) globalPostSelectionOidSet = globalPostSelectionOidSet.union(postSelectionOidSet) if len(postSelectionOidSet) > int(selectionBuffer): recentSelectionOidList = list(globalPostSelectionOidSet.difference(globalPreSelectionOidSet)) recentSelectionOidList.sort() if len(recentSelectionOidList) > 0: bufferReductionCount = bufferReductionCount + 1 arcpy.SelectLayerByAttribute_management("fl1", "NEW_SELECTION", oidFieldName + " in (" + ",".join(str(i) for i in recentSelectionOidList) + ")") for oidValue in globalPostSelectionOidSet: identifiedFeatures = identifiedFeatures + 1 oidDict[oidValue] = clusterId pctDoneUpdate = int(identifiedFeatures/float(featureCount) * 100) pctDoneDiff = pctDoneUpdate - pctDone if pctDoneDiff >= 1: for i in range(0,pctDoneDiff): arcpy.SetProgressorPosition() pctDone = pctDoneUpdate arcpy.AddMessage("Updating attribute table...") updateRows = arcpy.da.UpdateCursor(inLayer, ["OID@",clusterIdField]) for updateRow in updateRows: updateRow[1] = oidDict[updateRow[0]] updateRows.updateRow(updateRow) del updateRow, updateRows arcpy.AddMessage("Identified " + str(clusterId) + " cluster(s) for " + str(identifiedFeatures) + " features")
I apologize if this seems pedantic, but a recursive function is one that calls itself, not one that loops per se. You can often (always?) accomplish the same thing either way, but one or the other may be more efficient depending on what you're doing. Loops are definitely easier to understand though.
Note sure about your specific case or the exact logic you are employing in your workflow, but the general method of recursion relies on using a while loop.
myFC = r"C:\temp\test.gdb\test" featuresProcessedCount = 0 featureCount = int(arcpy.GetCount_management(myFC).getOutput(0)) while featuresProcessedCount < featureCount: do something featuresProcessedCount = featuresProcessedCount + 1
Signed in members can post, follow updates, and more. New here? Register a free account.
Find useful guides, FAQs, and documents to help you navigate and make the most of Esri Community.