Getting arcpy.da rows back as dictionaries

Though arcpy.da‘s cursors return rows as lists, you can easily transform these on-the-fly with just a little code on your part:

def rows_as_dicts(cursor):
colnames = cursor.fields
for row in cursor:
yield dict(zip(colnames, row))
with arcpy.da.SearchCursor(r'c:\data\world.gdb\world_cities', '*') as sc:
for row in rows_as_dicts(sc):
print row['CITY_NAME']

view raw
hosted with ❤ by GitHub

Or if you’d like to be able to use a syntax similar to the old arcpy cursors and do row.COLUMN_NAME to fetch a value, you could use namedtuples:

import collections
def rows_as_namedtuples(cursor):
col_tuple = collections.namedtuple('Row', cursor.fields)
for row in cursor:
yield col_tuple(*row)
with arcpy.da.SearchCursor(r'c:\data\world.gdb\world_cities', '*') as sc:
for row in rows_as_namedtuples(sc):
print sc.CITY_NAME

view raw
hosted with ❤ by GitHub

And then to get a little more sophisticated, what about an update cursor that lets you use dictionaries? Note that in this example the row will ALWAYS update without any intervention on your part once you go to the next one, so be careful:

def rows_as_update_dicts(cursor):
colnames = cursor.fields
for row in cursor:
row_object = dict(zip(colnames, row))
yield row_object
cursor.updateRow([row_object[colname] for colname in colnames])
with arcpy.da.UpdateCursor(r'c:\data\world.gdb\world_cities', ['CITY_NAME']) as sc:
for row in rows_as_update_dicts(sc):
row['CITY_NAME'] = row['CITY_NAME'].title()
print "Updating city name to {}".format(row['CITY_NAME'])

view raw
hosted with ❤ by GitHub

All the pieces are there in the Python standard library and arcpy.da to customize how you get your data in and out. The reason that arcpy.da returns lists and tuples is because they act as a sort of lowest-common-denominator of data structures, and in large datasets things like a dictionary key lookup benchmarks much, much slower than a simple list item assignment.

Retrieving Total Counts

In ArcGIS, the Summary Statistics tool is typically used to calculate a total count of unique occurrences in one field by a case field.
This is a table generated by the Summary Statistics tool showing the number of zip codes per state.

However, when you need this information in Python, you can avoid using the Summary Statistics tool and a search cursor. Instead, you can use the Counter class in the collections module. This will create a dictionary of keys and their counts. Here is the Python code and sample of the resulting dictionary:

Python code:

import collections
import arcpy

zipcode_cnt = collections.Counter(row[0] for row in arcpy.da.SearchCursor("ZipCodeBoundaries", "STATE"))


Counter({u’TX’: 1760, u’CA’: 1702, u’NY’: 1599, u’PA’: 1487, u’IL’: 1278, u’OH’: 1011, u’MO’: 984, u’FL’: 950, u’MI’: 908, u’IA’: 889, u’MN’: 862, u’VA’: 849, u’NC’: 741, u’WI’: 723, u’KY’: 719, u’GA’: 693, u’IN’: 689, u’KS’: 688, u’TN’: 606, u’AL’: 604, u’OK’: 591, u’WV’: 578, u’AR’: 572, u’NE’: 566, u’NJ’: 554, u’WA’: 536, u’MA’: 497, u’LA’: 478, u’CO’: 461, u’MD’: 435, u’ME’: 419, u’OR’: 400, u’MS’: 387, u’SC’: 382, u’ND’: 374, u’SD’: 352, u’AZ’: 334, u’MT’: 321, u’NM’: 284, u’CT’: 270, u’ID’: 252, u’VT’: 248, u’NH’: 243, u’UT’: 226, u’AK’: 213, u’NV’: 151, u’WY’: 141, u’PR’: 119, u’HI’: 90, u’RI’: 76, u’DE’: 59, u’DC’: 26})

Using a key, you can retrieve a value:

>>> print(zipcode_cnt[‘CA’])

See the collections module documentation for more information about the Counter class and other useful container datatypes.