0

My goal is to compare parcel IDs from two tables, one is a standalone shapefile and the other is a feature class inside a geodatabase (SQL Server). Both tables field name is "PARID" and the values are text in the table.

I would like this code to look for differences in list 1 from list 2 and then write the different parcels in a clean formatted text file.

however currently the text file output looks like this: enter image description here

I am facing few issues here, if I don't set the parcelList.append to (str(value)) I get the error:

TypeError: unhashable type: 'list'

but when I append the value as a string the list is only 1 item that contains all different values I compared, rather than having each parcelID its own item in the list.

My code is below:

import arcpy
#import os
import pprint

arcpy.env.workspace = r"C:\Users\path\tosde.sde"
legacyTable = "Database Connections\\database\_Legacy_Info"
NewParcelTable = r"\newParcels.shp"
legacyParcelList = []
NewParcelList = []
differentPCN = []
sql = "PARID LIKE '38%'"

print "generating list of existing legacy PCN's..."
with arcpy.da.SearchCursor(legacyTable,["Parid"],sql) as cursor:
    uniquePCN = sorted({row[0] for row in cursor})
    legacyParcelList.append(str(uniquePCN))
    #print uniquePCN
print "generating list of new PCN's..."
with arcpy.da.SearchCursor(NewParcelTable,["Parid"],sql) as cursor:
    uniquePCN2 = sorted({row[0] for row in cursor})
    NewParcelList.append(str(uniquePCN2))
    #print uniquePCN2



difference = set(NewParcelList).difference(legacyParcelList)
for item in difference:
    differentPCN.append(item)
print "the values below are in the New Parcel Shapefile list but not inside the Legacy Parceel List: " +'\n'
print "Writing output to text file..."
for item in differentPCN:
    pprint.pprint(item)
txtFile = r"C:\Users\differentPCNs.txt"
x = 0
try:
    for item in differentPCN:
        x +=  1
        f = open(txtFile,"w")
        f.write((str(x)) + ". "+ (item) + "\n")

finally:
    f.close()
print "file output is complete you can find it here: " + txtFile

I believe the issue is with the original search cursor and appending to new lists but not sure how to fix this.

  • I think the issue is that you've created a string of the list, rather than mapping the function str to to the list. In other words, you're ending up with "12345, 45678, 910111213" as a string, instead of ["12345", "45678", "910111213"] – smiller Oct 22 '18 at 15:31
  • how, I used list.append(str(value)) whats the correct way to do this? – NULL.Dude Oct 22 '18 at 15:36
  • You can either a) loop through the tuple, appending the string of each value to the tuple, or you can b) map the string function to your tuple, making a new list that has many string values. If you do this, you will need to extend, not append, your output. (This is because appending a tuple to a list will make an embedded tuple since lists can contain multiple data types.) My code snippet in answer below uses the more pythonic option b. – smiller Oct 22 '18 at 15:45
  • 1
    After staring at the code a little and confusing myself as to data types, I believe the unhashable error is due to some sort of dictionary comprehension {} going on instead of list comprehension. I'm still confused as to what value it's giving your dictionary... Either way please try the code suggestion and report back additional errors. – smiller Oct 22 '18 at 16:04
3

I think the issue is that you've created a string of the tuple, rather than mapping the function str to to the tuple. In other words, you're ending up with "(12345, 45678, 910111213)" as a string, instead of ["12345", "45678", "910111213"].

Suggested edit to lines 14-22 (the earlier and later lines look fine):

with arcpy.da.SearchCursor(legacyTable,["Parid"],sql) as cursor:
    uniquePCN = sorted({row[0] for row in cursor})
    legacyParcelList.extend(map(str,uniquePCN))
    print legacyParcelList

with arcpy.da.SearchCursor(NewParcelTable,["Parid"],sql) as cursor:
    uniquePCN2 = sorted({row[0] for row in cursor})
    NewParcelList.extend(map(str,uniquePCN2))
    print NewParcelList

EDIT: I just noticed that your original data for the parcel IDs is a string format anyway, so you can drop the conversion to string. I've edited below to use list comprehension instead, which allows us to cut off some lines. If there was something else you wanted within the dictionary, we can edit again.

with arcpy.da.SearchCursor(legacyTable,["Parid"],sql) as cursor:
    legacyParcelList = [row[0] for row in cursor]
    legacyParcelList.sort()
    print legacyParcelList

with arcpy.da.SearchCursor(NewParcelTable,["Parid"],sql) as cursor:
    NewParcelList = [row[0] for row in cursor]
    NewParcelList.sort()

As noted by @nmpeterson, make sure you convert both of the lists to sets for the difference method.

difference = set(NewParcelList).difference(set(legacyParcelList))
  • 1
    This gets him halfway there, but he still needs to convert both of the lists to sets to find the differences: difference = set(NewParcelList).difference(set(legacyParcelList)) – nmpeterson Oct 22 '18 at 16:04
  • He already has that in his code. – smiller Oct 22 '18 at 16:06
  • this worked like a charm no idea why its converting to a dict or tuple rather than list but your code suggestion fixed the problems – NULL.Dude Oct 22 '18 at 16:26
  • Oh,I see what you meant @npeterson. Yes, NULL.Dude make sure both lists are converted to sets for the set difference. – smiller Oct 22 '18 at 16:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.