I am trying to query a filed to find original parcels, i would like to create a filled and mark the ones that are original and don't have not split. Currently the field is a string with a length of 11. Some parcels have 5, some 8 and some 10 - not including the alph letter. Hopefully i have explained good what I am needing, i am just not sure how to do this. At first i thought of doing unique numbers but some how it would need to know if the first 5 digits are used, there are some duplicate numbers as well. I am kind of lost on how to proceed, if anyone has done something similar could share some code please?
the attributes are as follows for example;
R00062 (Original parcel)--> has R00062010 (Split parcel, next one below) - this is not one i need marked.
R00062010 - Not Original parcel
R32073114 - Not Original parcel
R32078 - Original parcel because there is no other parcel number associated with it, need this one mark in the new filed.
R32079 - Original parcel because there is no other parcel number associated with it,, need this one mark in the new filed.
R32081 - Original parcel because there is no other parcel number associated with it,, need this one mark in the new filed.
R32082012 - Not Original parcel
R32083012 - Not Original parcel
row[2] would mean that you have 3 elements in the field since python is 0-based, row[1] would be the second element... row[0], the first
I like Joshua Bixby 's code as it is simple. When you are in the UpdateCursor, just use the first 6 characters of the parcel id to check if it is in the original list, then set the flag. Here is that approach for you to test.
import arcpy
from collections import Counter
tbl = r'C:/Temp/ParcelNumberSample2.dbf'
# read parcel id into counter
parcel_count = Counter(
(pid[:6] for pid, in arcpy.da.SearchCursor(tbl,"PARCEL_NO"))
)
original = [] # an empty list for original parcels
for pid,cnt in parcel_count.items():
if cnt == 1: # origional parcels will only have a count of 1
original.append(pid)
# print original
with arcpy.da.UpdateCursor(tbl,["PARCEL_NO","Org_Par"]) as cursor:
for row in cursor:
if row[0][:6] in original: # trim row[0] to 6 characters and check if in original list
# print row[0]
row[1] = 'Orig'
# cursor.updateRow(row) # you can just update the flagged records by uncommenting this line and deleting the remaining lines
else: # or add an else to set non-original fields to a value
row[1] = 'N'
cursor.updateRow(row)
If you find that you do need the object id to do some other things, here's and updated version of my code that may give you some ideas. I used where OBJECTID IN ( nnn, nnn) in my SQL; you may need to make adjustments for your version. I was also testing with a file geodatabase where you might be testing with a shapefile.
import arcpy
tbl = r'C:/Temp/ParcelNumberSample2.dbf' # use your table name
# read oid and parcel_id into dictionary
parcels = [[r[0],r[1]] for r in arcpy.da.SearchCursor(tbl, ['PARCEL_NO', 'OBJECTID'])] # use your field names
# print parcels
# empty dictionaries for parents and children
parentFound = {} # format: { parent parcel id : object id }
childFound = {} # format: { parent parcel id : ( object id, count of items) }
for p in parcels:
parent = p[0][:6]
# print parent
if len(p[0]) > len(parent):
if parent in childFound.keys():
childFound[parent] = (p[1], 1 + childFound[parent][1] )# this will be last child found (by objectid)
else:
childFound[parent] = (p[1], 0)
else:
parentFound[parent] = p[1] # this will be last parent found (by objectid)
# print parentFound
# print childFound
objID = [] # empty list for object ids
for k in parentFound.keys():
if k not in childFound.keys():
# print k, parentFound, "parent is orig" # this is the parcelid and objectid of parent parcels, add to a list
objID.append(parentFound)
for k in childFound.keys():
if k not in parentFound.keys():
if childFound[1] < 1:
# print k, childFound[0], "child is orig" # this would be the parent parcelid that was NOT found, add to the list also
objID.append(childFound[0])
# print sorted(objID)
where = "OBJECTID IN ({})".format(str(sorted(objID)).strip('[]')) # substitute name of object id field
with arcpy.da.UpdateCursor(tbl,["OBJECTID","Org_Par"], where_clause=where) as cursor:
for row in cursor: # this will just update the rows where an original parcel id was found
print row
row[1] = 'Orig'
cursor.updateRow(row)
Excellent thank you!
Based on your requirements, and the possibility of duplicate parcel IDs, the following will generate a Python set of parcel IDs that meet your conditions. You can then use an update cursor to loop over the records and check whether the ID is in the set, and then flag the record accordingly.
>>> import arcpy
>>> from collections import defaultdict
>>>
>>> tbl = # path to table containing "PARCEL_NO" field
>>>
>>> unique_pids = defaultdict(set)
>>> with arcpy.da.SearchCursor(tbl, "PARCEL_NO") as cur:
... for pid, in cur:
... unique_pids[pid[:6]].add(pid)
...
>>> orig_pids = set().union(*(i for i in unique_pids.values() if len(i) ==1))
>>> orig_pids
set([u'R29688011', u'R29844', u'R29842010', u'R29835', u'R29846', u'R29833'])
>>>
Joshua Bixby, I always learn something from your code. Thanks.
I'll say the same thing about you too Randy! Both of you guys have a huge impact on what I do and how I code it!
I have learned a lot from all you guys on this forum.
It's nice to know there are people willing to help out!
@Joshua Bixby
@Randy Burton
@Joe Borgione
@Dan Patterson