I often have to take data I have received containing redundant text fields, and turn it into something more meaningful. Often, this will involve extracting unique values from a text field and converting it into a coded value domain.
This has the advantage of minimising data capture errors resulting from spelling mistakes, and provides a nice dropdown list in whichever interface I choose to represent the layer in (whether it be ArcMap, ArcGIS Online, Collector or a web viewer).
This script has gone through various revisions since I first wrote it two years ago. Let’s take a closer look at line 22:
gen_cvd = sorted(set(row for row in arcpy.da.SearchCursor(ftr, field_nam)), key=str.lower)
I’ve used a generator expression instead of a list comprehension to store all the values retrieved from the field using a search cursor. The amount of data I’m working with here didn’t really warrant the use of a generator – in fact, since I am performing multiple steps on this data (retrieving, dropping duplicates, sorting, looping), I probably should store it in a list.
However, I try to use different methods whenever I can so that I am always learning more about developing in my favourite language.
Using set, I remove duplicate values and then sort the values alphabetically. The cmp key str.lower is used to force case-insensitive sorting, otherwise uppercase values will be placed before lowercase values.
for dom_code, dom_value in enumerate(gen_cvd): arcpy.management.AddCodedValueToDomain(in_workspace=gdb, domain_name=cvd, code=dom_code, code_description=dom_value)
From Line 22, I use enumerate to add each value as a coded value to the attribute domain. Previously, I achieved this by doing the following:
vals = list(set([row for row in arcpy.da.SearchCursor(ftr, field_nam)])) codes = [c for c in xrange(0, len(vals)] domDict = dict(zip(codes, vals)) for pair in domDict: ...
By using enumerate, I have a counter which can be used as the code part of the coded value pair.