Here is more information regarding the performance of the provided solutions:
- Using
TableToNumPyArray
as below:
Code:
row=[x[0] for x in arcpy.da.TableToNumPyArray("Fitting","PROCESS")]
may give you the memory error if using Python 32bit (which comes with ArcGIS Desktop):
MemoryError: cannot allocate array memory
The number of features you will be able to convert into a numpy
array would depend on the type of column you will be counting unique values from. Speaking of a middle size unicode string field, you may hit the limits somewhere around 500,000 features.
If you get this error, you need to use Python 64bit which will let you create a larger arrays in memory.
- If your shapefile is not that big (mind that it has a .dbf attribute table limit of 2GB), you can use the
da.SearchCursor
which will outperform TableToNumPyArray
:
The timing for ~3 mln points feature class (running on ~3 mln shapefile gave the same results - 10secs for SearchCursor
and 15secs for numpy
array):
import timeit
print timeit.timeit(stmt="print list(set(f[0] for f in arcpy.da.SearchCursor(fc, 'municipality')))",
setup='''import arcpy; fc = r'C:\GIS\GDB_GeocodingOperational.gdb\PointAddress' ''', number=1)
>> 24.381339184
Doing the same thing using TableToNumPyArray
:
import timeit
print timeit.timeit(stmt="print list(set(f[0] for f in arcpy.da.TableToNumPyArray(fc,'municipality')))",
setup='''import arcpy; fc = r'C:\GIS\GDB_GeocodingOperational.gdb\PointAddress' ''', number=1)
>> 38.08295354
- Whenever you will construct sequences such as lists, consider using generators instead of lists constructed in a list comprehension or by iteratively appending values. This is because when you construct a list, it will be stored in your machine's memory. Constructing a large list may give you the out of memory error.
Code (rows
doesn't have any significant memory footprint; initialized instantly):
>>> rows = (f[0] for f in arcpy.da.SearchCursor(fc, 'municipality'))
>>> rows
<generator object <genexpr> at 0x197CBE68>
Code (rows
have eaten a good part of your machine RAM, almost 500MB for ~3mln features feature class; it also takes time to construct):
>>> rows = [f[0] for f in arcpy.da.SearchCursor(fc, 'municipality')]
>>> type(rows)
<type 'list'>
- If you will work with other data sources that are database based (file geodatabases or DBMS), you might like using
sql_clause
parameter of the SearchCursor
which can use the DISTINCT
prefix to get unique values from the database table column. In this way, you won't need to construct a list or an iterator and constructing a set from it.
However mind that using DISTINCT
prefix will take longer time to run (2-3 times longer), however, if performance is not critical, you might like using it to write a cleaner code as I think it's unnecessary to pull all the data and then filter it if you can provide a filter already when pulling the data.