I have 2 dictionaries (A and B). A is a new list of keys which is being checked against B. If a key is in B but not A (is an old value), I'm attempting to get the first value from the associated key in the dictionary (in this case an OBJECTID).
The issues I'm having are with line 32. As far as I can tell, this should iterate through all the keys in B, see if they're in A, and if not, write their value to a text file. As it happens, the text file is just getting the full list of old values (dictionary B) instead of only the ones not in both feature classes/dictionaries. Where are we going wrong?
I've attached the output text file
import arcpy
# Set environmental variables
arcpy.env.overwriteOutput = True
new = r"W:\Mapping\ArcGIS Online\ArcGIS Online Features.gdb\Collector_patch" #new feature class
old = r"W:\Mapping\ArcGIS Online\Upload.gdb\AGOL_Export" #old feature class
field = 'LinkKey', 'OBJECTID' #feature class fields to compare & return
fout = r"W:\Mapping\ArcGIS Online\FPC Plantations Features to Delete.txt" #output text file
a = {}
b = {}
#The old feature class is loaded into dictionary b
with arcpy.da.SearchCursor(old, (field)) as rows:
for row in rows:
if row[0] not in b:
b[row[0]] = [row[1]]
#The new feature class is loaded into dictionary a
with arcpy.da.SearchCursor(new, (field)) as rows:
for row in rows:
if row[0] not in a:
a[row[0]] = [row[1]]
#Below compares the dictionaries and extracts features with old Linkkeys"
fo = open(fout, "w")
for k, v in b.iteritems():
if k not in a.items()[0]:
print k
print v
fo.write(str(v[0]) + ',')
print "Linkkeys not in new feature class exported"
fo.close()
let's focus on the keys and skip the values for now.
noo = [1, 3, 5, 6, 7] # the new key list
old = [1, 2, 4, 6, 7] # the original key
found = [n for n in noo if n not in old]
found
[3, 5]
now you have the 'noo' keys that were in the 'old' key list. Use those for your slicing to get the values if needed.
FYI, your code will fail miserably in python 3 because substantial changes were made to dictionaries, so be forewarned if moving to ArcGIS Pro at any time soon.
Just a note of caution. It appears that LinkKey is not unique and that you are interested in the "first" occurrence of it. Result sets from database SQL queries do not guarantee order unless an ORDER BY clause is used, which means the "first" occurrence of a duplicate value returned from a cursor isn't guaranteed unless the cursor was setup with an ORDER BY clause.
So, instead of using
arcpy.da.SearchCursor(old, (field))
you will want to use
arcpy.da.SearchCursor(old, (field), sql_clause=(None, "ORDER BY OBJECTID"))
if you want to ensure the lowest OID is the "first" record for duplicate LinkKey values.
Thanks for the tip. Linkkey should be unique as well so this shouldn't be an issue for us. Good to know how to deal with it if this were the case though.
A few thoughts on form and function of your original code.
In terms of populating Python dictionaries, dictionary comprehensions are both idiomatic and efficient. The following code
b = {}
with arcpy.da.SearchCursor(old, (field)) as rows:
for row in rows:
if row[0] not in b:
b[row[0]] = [row[1]]
can be rewritten to
with arcpy.da.SearchCursor(old, field) as rows:
b = {k:[v] for k,v in rows}
NOTE: I am not clear why you are saving the OBJECTID value as a list in the dictionary, but I kept it in my rewritten code.
Not only can/should Python with statements be used with ArcPy cursors, they should definitely be used with Python file objects. The following code
fo = open(fout, "w")
# code processing data and writing output
fo.close()
can be rewritten to
with open(fout, "w") as fo:
# code processing data and writing output