Copy attribute values from one table to another, in a loop

2419
9
Jump to solution
06-05-2014 06:23 AM
MatthewWalker1
New Contributor III
I am trying to copy the attribute values from one table to another, inside a loop.  I am looping through one table and inside that loop I want to copy the attribute values to another table.  I have copied attribute values over before, but using JoinField, but I do not want to use that in this code, as I am already looping through records.  I have seen different code attempting to do this, but so far nothing has worked for me.  The code I'm working with is:

import arcpy import os import string import subprocess  arcpy.env.workspace = r"c:\Users\matt\Desktop\Ditch\Database\Centerline.mdb" assetFeatureClass = "[Assets]" assetrows = arcpy.UpdateCursor(assetFeatureClass,"[Processed] <> 'Y'","","","")  # for each row in the result set for row in assetrows:         print row.getValue("Ditch_ID")          #create asset         #Insert code to call out ArcObjects utility...         centerline = "[Pipeline_Centerline]"                  #update asset record attributes from asset table         rows = arcpy.UpdateCursor(centerline)         for row in rows:                 row.Ditch_ID = assetFeatureClass.Ditch_ID                  rows.updateRow(row)


I get an error that states:

Runtime error  Traceback (most recent call last):   File "<string>", line 24, in <module> AttributeError: 'str' object has no attribute 'Ditch_ID'


and I assume what is causing this is the row.Ditch_ID = assetFeatureClass.Ditch_ID section.  What I am trying to do in this section is to copy to the current record in the Centerline table the 'Ditch_ID' attribute value from the outer loop's record in the Assets table.  Also, I have to do this for several attributes (both tables have the same schema) and need to either iterate over the code for each, or somehow copy several attributes at once.
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
LT
by
Occasional Contributor
Hi Matthew,

assetFeatureClass is a string not a row object.  That's why you're getting the error message when you try to do this:

assetFeatureClass.Ditch_ID


What you really mean is row.Ditch_ID but you're using the variable named 'row' twice.  That's where the confusion probably arises. You should avoid using the same variable name ('row') on the inside loop that you're trying to use from the outside loop--For example, you could change the inner loop to

for rowC in rows:


That said, I don't think you really want a nested loop here.

I believe you could use the Python zip function to loop through both at once.  Here's an example of the zip function:

>>> listA = ['FID', 'Shape', 'COVER', 'RECNO'] >>> listB = ['OID', 'Geometry', 'String'] >>> for a, b in zip( listA, listB): ... print "a: ", a ,"      b: ", b ... a: FID           b: OID a: Shape       b: Geometry a: COVER       b: String


So your code would be something like:
assetRows = arcpy.UpdateCursor(assetFeatureClass,"[Processed] <> 'Y'","","","") centerRows = arcpy.UpdateCursor(centerline) for assetrow, rowCenter in zip(assetRows, centerRows):      centerRow.Ditch_ID = assetRow.Ditch_ID      #etc...

View solution in original post

0 Kudos
9 Replies
LT
by
Occasional Contributor
Hi Matthew,

assetFeatureClass is a string not a row object.  That's why you're getting the error message when you try to do this:

assetFeatureClass.Ditch_ID


What you really mean is row.Ditch_ID but you're using the variable named 'row' twice.  That's where the confusion probably arises. You should avoid using the same variable name ('row') on the inside loop that you're trying to use from the outside loop--For example, you could change the inner loop to

for rowC in rows:


That said, I don't think you really want a nested loop here.

I believe you could use the Python zip function to loop through both at once.  Here's an example of the zip function:

>>> listA = ['FID', 'Shape', 'COVER', 'RECNO'] >>> listB = ['OID', 'Geometry', 'String'] >>> for a, b in zip( listA, listB): ... print "a: ", a ,"      b: ", b ... a: FID           b: OID a: Shape       b: Geometry a: COVER       b: String


So your code would be something like:
assetRows = arcpy.UpdateCursor(assetFeatureClass,"[Processed] <> 'Y'","","","") centerRows = arcpy.UpdateCursor(centerline) for assetrow, rowCenter in zip(assetRows, centerRows):      centerRow.Ditch_ID = assetRow.Ditch_ID      #etc...
0 Kudos
MatthewWalker1
New Contributor III
Excellent, that worked!  Is there a way to loop through a set of attributes, or just list out each, such as:

centerrow.Ditch_ID = assetrow.Ditch_ID
        centerrow.Event_ID = assetrow.Event_ID
        centerrow.Comments = assetrow.Comments
        centerrow.Diameter = assetrow.Diameter
0 Kudos
LT
by
Occasional Contributor
If you're using ArcGIS 10.1 or higher, you could use the newer style Data Access cursors.  Then you could loop through the tuple of attribute values. Here's an example:

import arcpy

fc = 'C:/data.shp'
fields = [ 'Event', 'Comments', 'Diameter' ]

cursor = arcpy.da.SearchCursor( fc , fields )
for row in cursor:
     for attr in row:
           print attr
0 Kudos
MatthewWalker1
New Contributor III
I'm not sure how to implement that into the code to iterate over the tuple of attributes.  What would I put in place of the 'print attr' line, to assign the current attribute in the tuple to the appropriate attribute in the centerline feature I am trying to update?  In other words, what takes the place of the explicit "centerrow.Ditch_ID = assetrow.Ditch_ID" attribute assignment?

        cursor = arcpy.da.SearchCursor(centerline, fields)
        for row in cursor:
                for attr in row:
                        row.cursor = assetrow.? #what should this line look like?
                #centerrow.Ditch_ID = assetrow.Ditch_ID
                #centerrow.Event_ID = assetrow.Event_ID
                #centerrow.Comments = assetrow.Comments
                #centerrow.Diameter = assetrow.Diameter
                #print centerrow.getValue("Ditch_ID")
                #centerRows.updateRow(centerrow)
0 Kudos
LT
by
Occasional Contributor
Hi Matthew,

I think you need to use another zip, since you want to loop through both tuples of attributes at once. Something like this:

assetRows = arcpy.da.SearchCursor( fc1 , fields )
centerRows = arcpy.da.UpdateCursor( fc2 , fields )
for assetRow, centerRow in zip(assetRows, centerRows):
    for assetAttr, centerAttr in zip(assetRow, centerRow):
        centerAttr = assetAttr
    centerRows.updateRow(centerRow)
0 Kudos
RichardFairhurst
MVP Honored Contributor
Rewrite your code to use a dictionary.  It will perform 10 times faster.  Something like this works:

readFieldsList = ["OBJECTID", "RID", "MEAS", "X_COORD", "Y_COORD", "X_Y_LINK", "STNAME", "STNAMES", "X_Y_ROUTE"]
valueDict = {r[0]:(r[1:]) for r in arcpy.da.SearchCursor(readFC, readFieldsList)}

updateFieldsList =  ["FROM_OBJECTID","FROM_ROUTE_NAME","FROM_MEASURE","FROM_X_COORDINATE","FROM_Y_COORDINATE","FROM_X_Y_LINK","FROM_STREET_NAME","FROM_CROSS_STREETS","FROM_X_Y_ROUTE_NAME"]
with arcpy.da.UpdateCursor(updateFC, updateFieldsList) as updateRows:
    for updateRow in updateRows:
        ObjectIDVal = updateRow[0]
        if ObjectIDVal in valueDict:
            updateRow[1] = valueDict[ObjectIDVal][0]
            updateRow[2] = valueDict[ObjectIDVal][1]
            updateRow[3] = valueDict[ObjectIDVal][2]
            updateRow[4] = valueDict[ObjectIDVal][3]
            updateRow[5] = valueDict[ObjectIDVal][4]
            updateRow[6] = valueDict[ObjectIDVal][5]
            updateRow[7] = valueDict[ObjectIDVal][6]
            updateRow[8] = valueDict[ObjectIDVal][7]
            updateRow[9] = valueDict[ObjectIDVal][8]
            updateRows.updateRow(updateRow)


All you have to do is set your readFC and updateFC, change the field lists to match up your two feature classes and then include the correct number of transfer lines in the if condition of the loop.  Matches of about 100k records take about 20 to 30 seconds.
JudsonCrouch1
New Contributor III

Hi Richard,

I am relatively new to Python and search cursors. Can you explain what the value dictionary does?

Thanks in advance!

Judson

0 Kudos
RichardFairhurst
MVP Honored Contributor

First read my Blog post called Turbo Charging Data Manipulation with Python Cursors and Dictionaries.  It covers this subject in much more depth with several examples of how to apply the technique and it provides code that is more standardized which should be easier to customize to your needs.

As far as a Python dictionary it works like a real world dictionary.  If you look up a word in a dictionary (a dictionary key) you will find all kinds of information related to that word (the value associated with the key).  Python dictionaries offer is an extremely fast way to directly lookup related information through meaningful key values, as opposed to lists which only support a lookup using generally meaningless index number values or traversing the list in a loop.  Python dictionary keys are not limited to words and can be nearly anything that is an immutable value.  Tuples can be keys and can be used to create composite value keys (i.e., multi-field keys like the separate components of an address).  Lists and Dictionaries are mutable and cannot be used as keys, but they can be values associated with a lookup key.

JudsonCrouch1
New Contributor III

Thanks for the link to your blog post! That is exactly what I was looking for. I appreciate you taking the time to explain this.

0 Kudos