[GIS] Using Nested For Loop in ArcPy

arcgis-10.2arcpycursor

I have two vector layer files, 'hausnummer_cropped5' and 'gebaudepoints_cropped5 – Kopie2'. Both have a point geometry and I am trying to shift the locations of the gebaudepoints_cropped5 points onto the corresponding hausnummer_cropped5 points (there is a one-to-one correlation between them) if certain conditions are met (their original locations are slightly different). There are 68 gebaudepoints and 62 hausnummers.

The code I have written is this:

import arcpy

gebaudepoints_no = 68
hausnummer_no = 62
count = 0

with arcpy.da.UpdateCursor('hausnummer_cropped5', ['HAUSNR','STRASSE','SHAPE@XY']) as cursor1:

    for row1 in cursor1:

      with arcpy.da.UpdateCursor('gebaudepoints_cropped5 - Kopie2', ['ZA3',     'ZA2','GN5','SHAPE@XY']) as cursor2: 

         for row2 in cursor2:    

                if (row2[0] == row1[0]) and (row2[1] == row1[1]): # and (row2[2] > 0):

                  X = row1[2][0] 
                  Y = row1[2][1]  
                  count += 1 

                  cursor2.updateRow([row2[0], row2[1], row2[2], [(X),(Y)]])
                  #cursor2.deleteRow()

                  print count, gebaudepoints_no - count

There are 2 things I don't understand:

  1. After the code has been run, the value of 'count' is 92 and not 68. That means the loop has run 92 times even though it should have run only 68 times.

  2. Most of the gebaudepoints actually get placed on top of the hausnummer points, but around 5 to 6 don't, even though they meet the required conditions. However, if I use the cursor2.deleteRow() statement (which is written as a comment above), all the gebaudepoints get removed so that indicates that the code is actually going through those points as well, but it's just not shifting them.

I didn't have these two problems when I was using a different set of gebaudepoints and hausnummers so I'm wondering why this is occurring in this case.

I am using ArcGis 10.2.2

Best Answer

First of all if I were you, I would add two counters, one for each loop. After the script finishes you should simply print them out. Also note that the counter

Secondly the outer for loop runs your inner loop that compares your data. That way your count is increased for each match the inner loop finds. If you really want to see the real count value, you should put the line of code where you increment the count variable outside the if clause.

import arcpy
gebaudepoints_no = 68
hausnummer_no = 62
count = 0

with arcpy.da.UpdateCursor('hausnummer_cropped5', ['HAUSNR','STRASSE','SHAPE@XY']) as cursor1:

for row1 in cursor1:
  count1 += 1
  with arcpy.da.UpdateCursor('gebaudepoints_cropped5 - Kopie2', ['ZA3',     'ZA2','GN5','SHAPE@XY']) as cursor2: 
     count2=0
     for row2 in cursor2:    
            count2 +=1 #this one will increase waaaay too 
                       #much so just set it to zero before the loop and you're good
                       #but also note that it will show the length of 
                       #the last item in cursor1 within the cursor2
            if (row2[0] == row1[0]) and (row2[1] == row1[1]): # and (row2[2] > 0):
              #woo! the if condition is met lets print why here
              X = row1[2][0] 
              Y = row1[2][1]  
              count += 1 

              cursor2.updateRow([row2[0], row2[1], row2[2], [(X),(Y)]])
              #cursor2.deleteRow()

print("Counter for outer loop: "+str(count1)+" and the inner one "+str(count2))

What I would add to your code is, some sort of result printing, so you can display data when your if condition is met. Then you can see what points are missing and print that data out to see why they dont match and change the if clause correctly. So to direct you into where to look on what to print, I would the check values of your row2 list maybe you can find a label to print in there.

Related Question