Skip to main content
4 of 4
Commonmark migration

I would do it this way:

import arcpy
arcpy.env.workspace= r"Y:\Personal\jsmith\EGData.gdb"

fields=["OID@", "SHAPE@XY"] #tokens to access
D = arcpy.Describe("us_cities") # describe the US Cities to get the OID field name

with arcpy.da.UpdateCursor("cities_broken",fields) as UCur:
    # get ready to update each row
    for URow in UCur:
        # create a definition query
        dQ = "{} = {}".format(D.OIDFieldName,URow[0])
        with arcpy.da.SearchCursor("us_cities",fields,dQ) as SCur:
            # get the matching feature (if any)
            for SRow in SCur:
                # should only do this once or not at all if the OID isn't found
                URow[1] = SRow[1]
                UCur.updateRow(URow) # Important!! or the changes aren't saved

Your first cursor is an update cursor but the 2nd is a search cursor as you're only looking, not changing any values. Use the power of a definition query (where clause) in the docs to limit the matching row.. that is assuming the OID in broken cities matches the OID in US Cities.

I'm using "SHAPE@XY" but you could also just use "SHAPE@" to copy the geometry; SHAPE@XY is a tuple of (X,Y) but SHAPE@ is a geometry object, still copyable but only to a geometry field.

It's also important that you pick up the difference between assignment (=) and conditional (==). When you say X = 1 now the value of X is equal to 1, but if you say X == 1 then X does not change, it will either be True or False depending on the value of X; python will skip right over this without giving an error and you'll end up going nuts trying to find why X is none when you go to use it later.

By popular demand, a dictionary solution

import arcpy
arcpy.env.workspace= r"Y:\Personal\jsmith\EGData.gdb"

fields=["OID@", "SHAPE@XY"] #tokens to access

broken_city_OIDs=[66, 68, 61, 74, 86, 80, 116, 94, 96, 97]

Dict = {} # new empty dictionary
with arcpy.da.SearchCursor("us_cities",fields) as SCur:
    for SRow in SCur:
        if SRow[0] in broken_city_OIDs:
            Dict[SRow[0]] = SRow[1] # put the geometry tuple in the dictionary indexed by the OID

with arcpy.da.UpdateCursor("cities_broken",fields) as UCur:
    # get ready to update each row
    for URow in UCur:
        if URow[0] in broken_city_OIDs:
            # don't just assume that the key is in the dictionary, check!
            if URow[0] in Dict:
                URow[1]=Dict[URow[0]] # copy the dictionary geometry tuple to the updated row
                UCur.updateRow(URow)  # Important!! or the changes aren't saved

This is far more efficient than the nested loop. The process has two iterations

  1. Search through the match 'to' data and copy the necessary values into the dictionary.
  2. Update the required features with the in memory copy of the values stored in the dictionary.

Dictionaries are a little more advanced, they are like a list but store the values in a Key:Value pair, where a list is addressed from 0 numerically a dictionary can store keys of any type, you can have keys of strings and numbers in the same dictionary.. the only thing to watch for is that you don't inadvertently overwrite an existing value for a given key, a key must be unique.

Michael Stimson
  • 25.7k
  • 2
  • 35
  • 75