1

I have this piece of code:

#written on python 2.7 for ArcGIS Desktop 10.2.2

import arcpy

#set to folder where features are located
arcpy.env.workspace = "c:\\Users\\python_ex" #on windows use \\ instead of /


#---------------------------
#define variables for cursor
#---------------------------


"""SEARCHCURSOR"""
"""SearchCursor (in_table, field_names, {where_clause}, {spatial_reference}, {explode_to_points}, {sql_clause})"""
#field taken as "identifier". i.e. if column1 == a, take the value from the same row of column2
stable = "test2.shp"
sfield = ["column1", "column2"]
#where clause will be written in SQL and not assigned to variable
#more information can be found here http://resources.arcgis.com/en/help/main/10.2/index.html#//018w00000011000000

"""UPDATECURSOR"""
"""UpdateCursor (in_table, field_names, {where_clause}, {spatial_reference}, {explode_to_points}, {sql_clause})"""
#field taken as "identifier". i.e. if column 1 == a, take the value of the SearchCursor and insert into same row, but column2
utable = "test.shp"
ufield = ["column1", "column2"]
#where clause will be written in SQL and not assigned to variable
#more information can be found here http://resources.arcgis.com/en/help/main/10.2/index.html#/UpdateCursor/018w00000014000000/


#--------------------------
#start the loop
#--------------------------

svalues = [] #create list to store the values from the searchcursor

with arcpy.da.SearchCursor(stable, sfield, """"column1" = 'aa'""") as scursor: #SQL queries in python are build that way http://resources.arcgis.com/en/help/main/10.2/index.html#//002z0000001r000000
    for srow in scursor:
        svalues.append(srow) #append values to list
        print svalues
        with arcpy.da.UpdateCursor(utable, ufield, """"column1" = 'aa'""") as ucursor: #if used with statement, no need to close all the cursors
            for urow in ucursor:
                    ucursor.updateRow(svalues[-1]) #-1 always takes the last value of the list

I want to update every field in test.shp with each value found in test2.shp.

But, it takes only the last value found in the table of test2.shp and updates all the fields in test.shp with it.

Shouldnt the logic of the loop I created be: "take the first value that matches the criteria, go on to the updatecursor, update the first row matching the criteria and then go back to search and update the next row. etc"

Or am I totally mistaken?

1
  • You need to evaluate the result of your search cursor and compare it to your update cursor - i.e. IF SEARCHVALUE = UPDATEVALUE THEN UPDATE. Right now all you are doing is looking through the update cursor and updating all rows with the search cursor value.
    – dklassen
    Aug 7, 2014 at 16:36

2 Answers 2

6

If you really want to do it your way (which is fine in this case because it's just an exercise, but I would never recommend for any important work), it should be possible in the following manner:

with arcpy.da.UpdateCursor(utable, ["column2"], """"column1" = 'aa'""") as ucursor:
    with arcpy.da.SearchCursor(stable, ["column2"], """"column1" = 'aa'""") as scursor:
        for srow in scursor:
            svalue = srow[0]
            urow = ucursor.next()  # instead of a full "for urow in ucursor" loop each time
            urow[0] = svalue
            ucursor.updateRow(urow)

Alternatively:

svalues = [srow[0] for srow in arcpy.da.SearchCursor(stable, ["column2"], """"column1" = 'aa'""")]

with arcpy.da.UpdateCursor(utable, ["column2"], """"column1" = 'aa'""") as ucursor:
    for urow in ucursor:
        urow[0] = svalues.pop(0)
        ucursor.updateRow(urow)

Note: both of these will crash and burn if stable has fewer "aa" rows than utable.

13
  • So that's what pop does.... +1
    – Paul
    Aug 7, 2014 at 17:32
  • Thanks for the answer and for mentioning your concerns. As I wrote already in a comment on Eircas solution: it is just an exercise for me to understand cursors better. I know that this only works in a very special "environment" that I created for myself to practice. But it does the job and teaches me some stuff about cursors. I have a couple of questions regarding your answer. I understand that most of the operators you use are list comprehension operators. I learned already a lot about lists but I dont understand them the way you use them. Why srow[0] and urow[0]? Whats it doing?
    – four-eyes
    Aug 8, 2014 at 13:09
  • 1
    Since srow/urow are lists of attributes (in the same order as the fieldnames list specified in the cursor), you can use any normal list index to access values. Index 0 always returns the first (leftmost) item in the list, and -1 always returns the last. In this case, the lists are both of length 1 (i.e. [sfield] and [ufield]), so index 0 and index -1 will return the same thing.
    – nmpeterson
    Aug 8, 2014 at 13:15
  • Shouldnt svalue become longer with each iteration? Running your code with 0 does not work because the list looks like this: (u'aa', 342) and (u'aa', 9) and (u'aa', 99). Suprisingly my list with my code looks like this: first iteration: [(u'aa', 342)], second iteration [(u'aa', 342), (u'aa', 9)] and third [(u'aa', 342), (u'aa', 9), (u'aa', 99)]. Is yours a tuple? There are no []. Running your code with 0 does not work, it takes the aa. I had to replace it by a -1. I also had to remove the perenthisies around [ufield] and [sfield].
    – four-eyes
    Aug 8, 2014 at 13:26
  • 1
    Note that I avoided typing for urow in ucursor: at any point -- this has been replaced by ucursor.next(), which returns the next row in ucursor and allows full control over the rate at which we iterate through its rows. This way we only iterate through the full utable one time, keeping in step with the position of scursor on the other table. Setting urow[0] = svalue modifies the first value in the row list, to replace the current "column2" value with the one from the SearchCursor.
    – nmpeterson
    Aug 8, 2014 at 14:19
4

Since the UpdateCursor is nested inside the SearchCursor, it will loop through the cursor once for each srow. What it's actually doing (I assume) is running the full UpdateCursor for every SearchCursor value, but you're only seeing the last value since that is the last time it runs.

Also, the UpdateCursor will not stop at the first match -- it is being asked to run through every urow (i.e., all rows where column1 is aa).

If you can assume the two features are in the same order, try breaking the two cursors into separate loops:

with arcpy.da.SearchCursor(stable, sfield, """"column1" = 'aa'""") as scursor:
    for srow in scursor:
        svalues.append(srow) #append values to list
        print svalues
with arcpy.da.UpdateCursor(utable, ufield, """"column1" = 'aa'""") as ucursor:
    for index, urow in enumerate(ucursor):
        ucursor.updateRow(svalues[index])

If they aren't in the same order, a sort command prior to the loops could work, or comparing an additional value (e.g. the ObjectID) to ensure the values match up.

This actually might work better as a join and calculate field operation, unless this is just an exercise to learn cursors :)

6
  • +1 for join & calculate field. The proposed logic sounds horrendously error-prone.
    – nmpeterson
    Aug 7, 2014 at 16:19
  • It is an exercise. I do this for myself to understand more about cursors. They are not in the same order, but they have the same amount of feature classes (rows and "aa"'s? - not sure about the propper word). What would sort do? If I unnestthe updatecourser I would have to write every index of the list into the [index] field. That seems for a big table hardly possible?
    – four-eyes
    Aug 7, 2014 at 16:23
  • The index variable automatically increments. When you make the svalues list, each entry automatically gets a position index (0 for the first, 1 for the next, 2, 3, etc.). In the UpdateCursor loop, you're using index as a variable to access each individual element of the svalues list.
    – Erica
    Aug 7, 2014 at 16:31
  • 1
    You can use a list comprehension (or generator) to fill svalues: svalues = (row[0] for row in arcpy.da.SearchCursor(stable, sfield, """"column1" = 'aa'"""))
    – Paul
    Aug 7, 2014 at 17:08
  • You could make use a list comprehension (as Paul wrote, except with [] instead of () surrounding the whole thing) and use svalues.pop(0) to get the next value, in order.
    – nmpeterson
    Aug 7, 2014 at 17:19

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.