[GIS] Update value in one table (feature class) by coping it from another table. The match between table is done on values from another field

arcgis-desktoparcpycursordictionary

I have two tables (actually both are feature classes in filegeodatabase).
They pretty much identical except. one is in lat/lon. second one is projected.
both have field line_length and objectid.
Second one has values in field line_length.
how do I copy these values (based on objectid field match) from second table into the fist one.

The snippet of my code:

Part first. Create dictionary from second dataset. Copy values from second dataset into dictionary. value that I will be using for matching is goint to be key, the value I need to copy to my first dataset are going to be values. This part works ok.

my_dict = dict()
fc = r'H:\NetworkAnalyst\TopologyVer4\firetrials.gdb\ft_mb_afterIteration_lambert'
fields = ['OBJECTID', 'line_length']
with arcpy.da.SearchCursor(fc, fields) as cursor:
    for row in cursor:
        a_id = row[0]
        b_len = row[1]
        my_dict[a_id] = b_len

print "dictionary done"

Second part. Update field "line_length" in the first dataset with values from second dataset, which are now in dictionary. Match records by OBJECTID field.

rows = arcpy.UpdateCursor(r'H:\NetworkAnalyst\TopologyVer4\firetrials.gdb\ft_mb_afterIteration_lambert')
for key, value in my_dict:
    match_value = key
    update_value = value
    for row in rows:
        print match_value, update_value
        if row.OBJECTID == match_value:
        rows.setValue("line_lenght", update_value)

I am getting an error for line
for key, value in my_dict:

Error is " TypeError: 'int' object is not iterable "

Any ideas?

Best Answer

Pre-code:

import arcpy

fc_src = r"C:\ArcTutor\BuildingaGeodatabase\Montgomery.gdb\Landbase\Blocks"
fc_dest = r"C:\ArcTutor\BuildingaGeodatabase\Montgomery.gdb\Landbase\Blocks_Geo"

What Vince was referring to as nested cursors:

Code:

with arcpy.da.SearchCursor(fc_src,["OBJECTID","Acres"]) as search_cur:
    for search_row in search_cur:
        with arcpy.da.UpdateCursor(fc_dest,["OBJECTID","AcresObtained"]) as upd_cur:
            for upd_row in upd_cur:
                if upd_row[0] == search_cur[0]:
                    upd_row[1] = search_row[1]
                    upd_cur.updateRow(upd_row)

A dictionary based solution (I use this most often):

search_feats = {f[0]:f[1] for f in arcpy.da.SearchCursor(fc_src,["OBJECTID","Acres"])}

with arcpy.da.UpdateCursor(fc_dest,["OBJECTID","AcresObtained"]) as upd_cur:
    for upd_row in upd_cur:
        upd_row[1] = search_feats[upd_row[0]]
        upd_cur.updateRow(upd_row)

Additional comments:

  • always use the da cursors (arcpy.da.UpdateCursor, not arcpy.UpdateCursor)
  • use the list/dictionary comprehensions, particularly when iterating arcpy cursors

Update: explaining some of the concepts in the dictionary alternative.

f[0]:f[1]

means we are taking the first value in the tuple (cursor returns a list of two-values tuple, such as [(12,45.678),(13,78.654)], which represents the OBJECTID, and make it a key of the dictionary; we map this key into a value of Acres (second element in the tuple).

This is the same as writing:

search_feats = {}
for f in arcpy.da.SearchCursor(fc_src,["OBJECTID","Acres"]):
    search_feats[f[0]] = f[1]

The dictionary comprehensions are just faster and less code can be written and then read.

Another thing.

upd_row[1] = search_feats[upd_row[0]]

Here we assign the AcresObtained field (which is the second value in the tuple in the update cursor) to be a value that is found for this OBJECTID key in the dictionary search_feats.

Could be written as

row_update_objectid = upd_row[0]
upd_row[1] = search_feats[row_update_objectid]
Related Question