Trying to use dictionary key with UpdateCurosor

2129
11
Jump to solution
10-09-2020 08:32 AM
2Quiker
Occasional Contributor II

I can do it with a basic arcpy.da.UpdateCurosr but I am trying to figure out how to use arcpy.da.UpdateCurosr with dictionary key. I am trying to populate Field1 if the row is blank but if not then continue on to the next row. I have the following but I get error,

upd_row[0] = search_feats[upd_row[1]] #FIELD_2
KeyError: 'Blah Text'
>>> 

flds = ['Field1','Field']
search_feats = {f[0]:f[1:] for f in arcpy.da.SearchCursor(fc1, flds)}


with arcpy.da.UpdateCursor(fc1, flds) as upd_cur:
     for upd_row in upd_cur:
        #if upd_row[0] is None:
        if upd_row[0] != None:
        #if upd_row[0] in ("", ' ', None):               
            upd_row[0] = search_feats[upd_row[1]] #FIELD1
            upd_cur.updateRow(upd_row)


del upd_cur‍‍‍‍‍‍‍‍‍‍‍‍‍‍
1 Solution

Accepted Solutions
RandyBurton
MVP Alum

I created a quick feature for illustration.  It contains the following:

To copy the value from Field2 to Field1 using a dictionary, I modified your code and added some explanation:

fc1 = 'DictionaryTest'

flds = ['OBJECTID','Field1','Field2']

# for clarity, put f[1:] in parenthsis - this will be a tuple
search_feats = {f[0]:(f[1:]) for f in arcpy.da.SearchCursor(fc1, flds)}

# Produces this dictionary: {1: (u'', u'AA2'), 2: (u'bb1', u'BB2'), 3: (None, u'CC2')}
# key = 1, value[0] = empty string, value[1] = 'AA2'
# key = 2, value[0] = bb1, value[1] = 'BB2'
# key = 3, value[0] = None/Null, value[1] = 'CC2'



with arcpy.da.UpdateCursor(fc1, flds) as upd_cur:
    for upd_row in upd_cur:

        # if upd_row[0] == None:
        # this is the OBJECTID, it should always have a value

        #  is the OBJECTID in the search_feats dictionary?
        if upd_row[0] in search_feats.keys():

            # upd_row[1] is 'Field1' and upd_row[2] is 'Field2'
            # search_feats[upd_row[0]] is the dictionary key, 'Field2' is the second value of the dictionary [1]

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

            upd_cur.updateRow(upd_row)

        # OBJECTID not in dictionary
        else:
            pass‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

The result is:

Field1 now contains the same values as Field2.  For something this simple, I wouldn't use a dictionary.  It would work best in place of joining two features on a common field to copy values from one feature to the other.  It may also be helpful in some other cases.

Hope this helps.

View solution in original post

11 Replies
JoeBorgione
MVP Emeritus

What is the error you are getting?

Here is how I've done something similar in the past:

tableFields = ['SITEID','SITE_GUID']
source = r'some\path\to\data table'

guidDict = {r[0]:(r[1:]) for r in arcpy.da.SearchCursor(source,tableFields)}

with arcpy.da.UpdateCursor(updateTable,updateFields) as updateRows:
    for updateRow in updateRows:
        keyValue = updateRow[0]
        if keyValue in guidDict and updateRow[1] == None:
            updateRow[1] = guidDict[keyValue][0]
            updateRows.updateRow(updateRow)
        else:
            pass
That should just about do it....
2Quiker
Occasional Contributor II

Joe, thanks for the response. I see but after using your code and implementing my data and running the code field1 is not being populated with field2 if the fied1 rows are blank.

The error I was getting was with my code was;

Traceback (most recent call last):
  File "D:\GIS Folder Scripts\UpdateFiledBlanks.py", line 10, in <module>
    upd_row[0] = search_feats[upd_row[1]] #FIELD_2
KeyError: 'Final Plat'

0 Kudos
RandyBurton
MVP Alum
flds = ['Field1','Field']
search_feats = {f[0]:f[1:] for f in arcpy.da.SearchCursor(fc1, flds)}

In this bit of your code, 'Field1' id becoming the dictionary key f[0].  A dictionary key cannot be blank.  Field1 should be unique, something like an object id ('OID@' for example)

2Quiker
Occasional Contributor II

That was my initial thought and makes sense but if Field1 is unique pass field2 and field3 to updatecursor and update field1 with field2 if filed1 is blank? I am still trying to make sense of Dictionary keys and how to loop through them.

0 Kudos
JoeBorgione
MVP Emeritus

put your latest iteration of your code up and I'll see if I can figure it out.

I think the better way to see if a value is None (<Null>) you should use

is None instead of == None

The thing you need to be sure  is you are checking for it and doing something when it is null and something else when it isn't.

if x is not None:
   pass
else:
   do something

#### or

if x is None:
   do something
else:
    pass


‍‍‍‍

See Can you explain in simple terms what 'is not None' in Python 3.x is? - Quora  ; a guy named Troy Hoffman gives a good explanation in his comment.

That should just about do it....
2Quiker
Occasional Contributor II

This is what I've got, I posted the wrong one at first.

I get no errors but field1 row doesn't get populated with field2 is field1 row is blank.

flds = ['field1','field2']

search_feats = {f[0]:f[1] for f in arcpy.da.SearchCursor(fc1,flds)}

with arcpy.da.UpdateCursor(fc1,flds) as upd_cur:
     for upd_row in upd_cur:
          if upd_row[1] == None:
               upd_row[1] = search_feats[upd_row[0]]
               upd_cur.updateRow(upd_row)  
          else:
               pass
del upd_cur  ‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos
RandyBurton
MVP Alum

I created a quick feature for illustration.  It contains the following:

To copy the value from Field2 to Field1 using a dictionary, I modified your code and added some explanation:

fc1 = 'DictionaryTest'

flds = ['OBJECTID','Field1','Field2']

# for clarity, put f[1:] in parenthsis - this will be a tuple
search_feats = {f[0]:(f[1:]) for f in arcpy.da.SearchCursor(fc1, flds)}

# Produces this dictionary: {1: (u'', u'AA2'), 2: (u'bb1', u'BB2'), 3: (None, u'CC2')}
# key = 1, value[0] = empty string, value[1] = 'AA2'
# key = 2, value[0] = bb1, value[1] = 'BB2'
# key = 3, value[0] = None/Null, value[1] = 'CC2'



with arcpy.da.UpdateCursor(fc1, flds) as upd_cur:
    for upd_row in upd_cur:

        # if upd_row[0] == None:
        # this is the OBJECTID, it should always have a value

        #  is the OBJECTID in the search_feats dictionary?
        if upd_row[0] in search_feats.keys():

            # upd_row[1] is 'Field1' and upd_row[2] is 'Field2'
            # search_feats[upd_row[0]] is the dictionary key, 'Field2' is the second value of the dictionary [1]

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

            upd_cur.updateRow(upd_row)

        # OBJECTID not in dictionary
        else:
            pass‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

The result is:

Field1 now contains the same values as Field2.  For something this simple, I wouldn't use a dictionary.  It would work best in place of joining two features on a common field to copy values from one feature to the other.  It may also be helpful in some other cases.

Hope this helps.

2Quiker
Occasional Contributor II

Awesome, thanks for the explanation on this.

0 Kudos
JoeBorgione
MVP Emeritus

I get no errors but field1 row doesn't get populated with field2 if field1 row is blank.

There is huge difference between None and a Blank or Empty field.  The None value, which is python's way of denoting the <Null> value is a specific value: NULL.  A blank or empty field is not null; it has at least one space in it.  Numeric and date fields can't have a space in them, so they are Null by default.  However, a space in a text field (or fifty spaces) will torpedo your use of is None or == None every time.  Check your data!  I can't tell you how many calories I've burned converting blank fields to Null values. ( But I'm still pudgy...)

Dictionaries are relatively simple once you get used to using them.  They are in the form of:

Key:Value

All the keys must be unique, and you can only have one value per key. Remember though, the value can be a tuple so that's a way to cheat the one key one value rule. (You can 'nest' dictionaries too, but that gets too weird for me.) Think about a any table in a database; it's basically a dictionary.  It has an object id (key) and a tuple of values:

{1:('feild1','field2', 'field...n'),

2:('feild1','field2', 'field...n'),

3:('feild1','field2', 'field...n')}

etc

The trick with dictionaries and update cursors is being able to identify the unique key and extract the value associated with that unique key that you want.

Hope this helps.

That should just about do it....