Select unique values from field using selectbyattribute

5309
16
03-11-2018 06:51 PM
wwnde
by
Occasional Contributor

I am a vety new to python. I have done the script below which identifies unique values and lists them. That goes ok. The next thing, I want it to iterate through the filed LinkKey as it selects similar LinkKeys and saves them in a work space.

All i get is a message saying zero records selected. I suspect the issue is in my whereclause.

Any help?

Tags (1)
0 Kudos
16 Replies
RandyBurton
MVP Alum

In your code you are using a function to find a set of unique values, but the function isn't returning anything (therefore, it equals None).  Add a line to "return uniqueValues".

def unique(fc, field):
    values = [row[0] for row in arcpy.da.SearchCursor(fc,(field))]
    uniqueValues = set(values)
    print(uniqueValues)

    return uniqueValues  # unique should return a value

Vals = unique(fc, field)
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Also if the goal is to count the number of records with a certain attribute, you can modify the function to return a count of the unique records and you will not need to use SelectLayerByAttribute.  You would use just one Search Cursor.

import arcpy

fc = r'C:\Path\To\file.gdb\feature'
field = 'FieldName' # not an alias

d = {}

with arcpy.da.SearchCursor(fc, (field)) as rows:
    for row in rows:
        if row[0] not in d:  # add to dictionary with value of 1
            d[row[0]] = 1
        else: # it is in dictionary, just incrment counter
            d[row[0]] += 1


for k, v in d.iteritems(): # print results
    print k, v


# ===  same idea, but as a function

def unique2(fc, field):
    ud = {}
    with arcpy.da.SearchCursor(fc, (field)) as rows:
        for row in rows:
            if row[0] not in ud:
                ud[row[0]] = 1
            else:
                ud[row[0]] += 1
    return ud

Vals2 = unique2(fc, field)

print 'Vals2:'
for k, v in Vals2.iteritems():
    print k, v‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
ChrisParkin2
New Contributor

I did something similar earlier in the week. essentially you need to iterate over the unique list, you don't need the 2nd cursor.

import arcpy
arcpy.env.workspace = r'C:\Workarea\Temp\geonetexample.gdb'
# Build list of unique LinkKeys
unique_LinkKey_List = []
with arcpy.da.SearchCursor('PLOTS_Test_lyr', ['LinkKey']) as cursor:
    for key in cursor:
        if key[0] not in unique_LinkKey_List:
            unique_LinkKey_List.append(key[0])

# iterate over unique keys
for key in unique_LinkKey_List:
    whereClause = "LinkKey = '%s'" % key
    arcpy.SelectLayerByAttribute_management('PLOTS_Test_lyr', 'NEW_SELECTION', whereClause)
    
    outFC = 'Key_FC_%s' % key
    arcpy.CopyFeatures_management('PLOTS_Test_lyr', outFC)
    cnt = arcpy.GetCount_management('PLOTS_Test_lyr')
    arcpy.AddMessage('Exported %s Records as %s' % (cnt, outFC))
0 Kudos
wwnde
by
Occasional Contributor

Though this script does what I need to do, I would be much happier if it can select within the selected features based on field CWY. CWY has five sets of attributes which could apply to any of the attributes in ROUTE_NE_ID. How can I do an exp for the below command without necessarily a definition for unique values in CWY again? 

arcpy.SelectLayerByAttribute_management(road_lyr, 'SUBSET_SELECTION', exp)
0 Kudos
ChrisParkin2
New Contributor

I'd probably use a definition query to make the initial selection, then use a search cursor on the definition query.

At least that's what I did last week.

Though I've probably misunderstood the question.

# Chris Parkin, 14/3/2018
import arcpy

mxd = arcpy.mapping.MapDocument("CURRENT")
df = arcpy.mapping.ListDataFrames(mxd, "Layers")[0]

# This must be sorted chronologically beforehand
visitLayer = arcpy.mapping.ListLayers(mxd, 'Visits_Inspectors_XY_XY_SortedDatetime', df)[0]

# Build list of inspectors
inspectors = []
with arcpy.da.SearchCursor(visitLayer, ['Assigned_inspectors']) as cursor:
    for inspector in cursor:
        if inspector[0] not in inspectors:
            inspectors.append(inspector[0])

lastIter = ['#','#','#','#','#','#','#','#','#','#']
for inspector in inspectors:
        visitLayer.definitionQuery = "Assigned_inspectors = '%s'" % inspector
        with arcpy.da.UpdateCursor(visitLayer, ['last_action_date', 'X_Inspector', 'Y_Inspector', 'X_Visit', 'Y_Visit', 'X_Start', 'Y_Start', 'X_End', 'Y_End', 'Day']) as cursor:
            for inspector in cursor:
                if inspector[9] == lastIter[9]:
                    # Start
                    inspector[5] = lastIter[3]
                    inspector[6] = lastIter[4]
                    # End
                    inspector[7] = inspector[3]
                    inspector[8] = inspector[4]
                else:
                    # Start
                    inspector[5] = inspector[1]
                    inspector[6] = inspector[2]
                    # End
                    inspector[7] = inspector[3]
                    inspector[8] = inspector[4]
                cursor.updateRow(inspector)
                lastIter = inspector
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos
wwnde
by
Occasional Contributor

Hi Chris

That may not be suitable here, this script is part of a larger model. It searches a database and gives outputs to be fed in consequent processes. May not be feasible to pull out an mxd and iterate.  All I need is a suitable expression that will pull out a subselection and copy features. Does that make sense?

0 Kudos
wwnde
by
Occasional Contributor

Thanks, Randy, Dan, Joe and Chris. Very helpful insights. Didn't have time in the week to come back to it. Borrowing from your posts, it ended up well. Have come up with the below code and fed it into a model builder tool. It worked. Thanks

# Import arcpy module
#Identify unique linkkeys, select and save them for input into bulk distance network analyst model
import arcpy


# Set environmental variables

arcpy.env.overwriteOutput = True

arcpy.env.workspace =r"C:\Users\William\Desktop\mt barker\DemoInventory.gdb"
fc = 'PLOTS_Test'
field = 'LinkKey'

#def unique values in LinKey method 1 and it works
def unique(fc, field):
 values = [row[0] for row in arcpy.da.SearchCursor(fc, field)]
 uniqueValues = set(values)

 print(uniqueValues)
 
 return uniqueValues # unique should return a value 

unique_LinkKey = unique(fc, field)#as a function


print 'unique_LinkKey:'


PLOTS_Test_lyr = arcpy.MakeFeatureLayer_management("PLOTS_Test", "PLOTS_Test_lyr")#layer from the feature class

for individual in unique_LinkKey:
 whereClause = "LinkKey = '%s'" % individual
 print(whereClause)
 arcpy.SelectLayerByAttribute_management(PLOTS_Test_lyr, 'NEW_SELECTION', whereClause)
 
 
 arcpy.CopyFeatures_management(PLOTS_Test_lyr, "sasa1")#Copying features from selection
 cnt = arcpy.GetCount_management("PLOTS_Test_lyr") # Counting the selected and copied features
 print("The number of selected records is: " + str(cnt))
 arcpy.SelectLayerByAttribute_management(PLOTS_Test_lyr, "CLEAR_SELECTION")
 print("The number of selected records is: " + str(cnt))

0 Kudos
DanPatterson_Retired
MVP Emeritus

To simply get the unique values from a field, whether you are using cursors for other purposes or not, you can use the table/featureclass and pull out the unique values from it 

# --- one import
import numpy as np

# --- you already know the table source
in_tbl = 'C:\\GIS\\A_Tools_scripts\\Numpy_arc\\Numpy_arc.gdb\\sample_1000'

# --- ditto for the field name, use an arcpy.da function
arr = arcpy.da.TableToNumPyArray(in_tbl, field_names=['County'])

# --- and a simple numpy function
uni = [i[0] for i in np.unique(arr)]

# --- there it is (actually, they were the unique values in the field)
uni
['A', 'B', 'C', 'D']