1

Generate Near Table or Near can be used on a single Feature Class to find the nearest feature to each feature.

 arcpy.GenerateNearTable_analysis(featureClass, featureClass, pairsTable)

3 Example Points A, B and C

This results in two rows for each pair, when feature A is nearest feature B and when feature B is nearest feature A. Feature C may also be nearest feature B. I'm trying to come up with a table of unique pairs using arcpy (e.g. keep A-B, C-B, but remove B-A).

I started out doing this using a selection based on a cursor, and it seems to work but it is extremely slow (~20min for 1300 points), there must be a simpler way.

 arcpy.MakeFeatureLayer_management(pairsTable, "lyr")
 pairs_lst=[]
 with arcpy.da.SearchCursor(pairsTable, ["IN_FID", "NEAR_FID"]) as cursor:
      for row in cursor:
           pairs_lst.append([row[0],row[1]])
           if [row[1], row[0] not in pairs_lst:
                exp = '"IN_FID" = ' + str(row[0])
                arcpy.SelectLayerByAttribute_management("lyr", "ADD_TO_SELECTION", exp)
 arcpy.CopyFeatures("lyr", pairsTable2)
2

This field calculator expression took 0.65 seconds to populate new field by 1 - first occurrence or 2 - twin in 10000 large table.

aDict={}
def FirstOrNot(a,b):
 key=tuple(set([a,b]))
 if key in aDict:  return 2   
 aDict[key]=0
 return 1

---------------------------

FirstOrNot(!FID!, !NEAR_FID! )

This is a very big zoom:

enter image description here

Points symbolised by this field value (1 - green, 2 - red) and labelled by FID/NEAR_FID.

2

I think the most inefficient part of your code is Select by Attribute part which requires relatively high overhead to add marked item to your current selection. First create a new SHORT field in your table to mark the desired pairs. And then I suggest you to first create a Python set with row[0] and row[1] as converted to string and with a delimiter first, and then evaluate this to calculate values in newly created field. For example (EDITED CODE):

import arcpy

arcpy.AddField_management(pairsTable,'IN_OR_OUT','SHORT')

pair_set=set()
with arcpy.da.SearchCursor(pairsTable,["IN_FID", "NEAR_FID"]) as cursor:
    for row in cursor:
        pair_set.add('|'.join(sorted([str(row[0]),str(row[1])])))

with arcpy.da.UpdateCursor(pairsTable,["IN_FID", "NEAR_FID", "IN_OR_OUT"]) as cursor:
    for row in cursor:
        key='|'.join(sorted([str(row[0]),str(row[1])]))
        if key in pair_set:
            row[2]=1
            pair_set.remove(key)
        else:
            row[2]=0

        cursor.updateRow(row)

Finally, just filter the rows with the desired value in the newly added field.

  • Sorting to get the desired set is a good idea. However, in the hypothetical case in the question, where point C (3) is nearest B (2) but B (2) is nearest A (1) the update cursor would reject the C-B (3|2) pair (else: =0) because it is different than the value in the set (['2|3']) which doesn't exist since B is nearest A. – jbosq Jul 20 '16 at 15:05
  • I think this is up to how you set parameters of Generate Near Table tool, not to removal of duplicates. In fact answer does not look into if any features represented by their FIDs are the nearest, just sorts these FIDs and checks out if it is unique. In fact having 3-2 in your table but not 2-3 is lesser importance since this relation is reciprocal. – fatih_dur Jul 20 '16 at 20:57
  • Let me clarify: your solution removes a pair that is unique (['3|2']) because its reciprocal (['2|3']) is (correctly) not in the near table. – jbosq Jul 20 '16 at 22:54
  • My apologies, you have a point there. Removing the items from the set once triggered should resolve the issue. Please see the edited code. – fatih_dur Jul 21 '16 at 0:17
  • For the sake of simplicity, I preferred to suggest two-step process, creating the set and then evaluating it. Actually, all can be consolidated into one loop by using dictionary's setdefault method, which resembles @FelixIP's answer. – fatih_dur Jul 21 '16 at 4:09

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.