Berechnen von fortlaufenden Zahlen in sortierte Tabellen mit ArcGIS Desktop?

11

Gibt es eine Möglichkeit, ein sortiertes Feld mit fortlaufenden Zahlen zu berechnen ? Ich habe gesehen, wie die Feature-Class "Sortieren" zur Berechnung des sequentiellen ID-Felds mit ArcGIS Field Calculator verwendet wird. das beschreibt, wie fortlaufende Zahlen berechnet werden, aber dies wird immer in der FID-Reihenfolge berechnet, nicht in der sortierten Reihenfolge.

#Pre-logic Script Code:
rec=0
def autoIncrement(): 
    global rec 
    pStart = 1  
    pInterval = 1 
    if (rec == 0):  
        rec = pStart  
    else:  
        rec += pInterval  
    return rec

#Expression:
autoIncrement()

Ein Beispiel dafür, was ich versuche zu tun. Ich habe eine erweiterte Sortierung verwendet, um nach Jahr, Monat, Tag zu sortieren, und möchte jetzt fortlaufende Nummern im SeqFeld haben. Sie werden sehen, dass mein OBJECTIDFeld nicht in Ordnung ist, sodass der obige Code nicht funktioniert.

Geben Sie hier die Bildbeschreibung ein

Kann dies entweder im Feldrechner oder mit einem Update-Cursor in arcpy erfolgen?

Midavalo
quelle
In ArcObjects mit einem ITableSort sollten Sie dazu in der Lage sein. Nicht so sehr in Python. Wie ist die Tabelle sortiert? Sie können es bis zu einem Wörterbuch mit OID und Sortierfeld lesen, das Wörterbuch sortieren, ein weiteres Wörterbuch mit OID und Wert erstellen, das sortierte erste Wörterbuch iterieren, um den Wert dem zweiten zuzuweisen, und dann den Cursor durch Zuweisen mit dem zweiten Wörterbuch ... a ein bisschen rumspielen, aber das ist alles, was ich mir vorstellen kann, ohne ArcObjects zu verwenden.
Michael Stimson
@ MichaelMiles-Stimson das ist keine schlechte Idee, ich könnte es wahrscheinlich in Wörterbücher laden, um eine Sortierreihenfolge zu bestimmen und diese Werte dann in die Seq zu schreiben.
Midavalo
So habe ich es schon mal gemacht und es hat gut funktioniert. Ich kann meinen Code momentan nicht finden. Es war einmalig, also wahrscheinlich auf einer meiner Sicherungsdiscs ... Wenn ich darauf stoße, werde ich als Antwort posten - vorausgesetzt, es gibt noch keine gute Antwort auf diese Frage.
Michael Stimson
Ich war immer verärgert darüber, dass dies in ArcGIS nicht einfach möglich ist. In MapInfo ist dies dagegen trivial. Der einfachste Weg, auf den ich gestoßen bin, ist die Verwendung des Sortierwerkzeugs, aber das erstellt einen anderen Datensatz, den Sie wieder verbinden müssten.
Fezter
Ihre Python-Syntax funktioniert perfekt, danke dafür. Ich frage mich nur, ob es möglich ist, die erste Zeile mit 1 statt mit 0 zu beginnen. Wenn es möglich ist, können Sie mir den Code dafür geben. Haben Sie ein gutes Wochenende Fred
Fred

Antworten:

13

"Lösung" mit 2 sortierten Feldern (aufsteigend):

mxd = arcpy.mapping.MapDocument("CURRENT")
lr=arcpy.mapping.ListLayers(mxd)[0]
tbl=arcpy.da.TableToNumPyArray(lr,("oid","A","B"))
bs=sorted(tbl, key=lambda x: (x[1], x[2]))
def sortSeq(fid,a,b):
 for i,ent in enumerate(bs):
   if ent[0]==fid: return i

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

sortSeq( !OID!, !A!, !B! )

Geben Sie hier die Bildbeschreibung ein

AKTUALISIERTE VERSION:

mxd = arcpy.mapping.MapDocument("CURRENT")
lr=arcpy.mapping.ListLayers(mxd)[0]
tbl=arcpy.da.TableToNumPyArray(lr,("oid","A","B"))
bs=sorted(tbl, key=lambda x: (x[1], x[2]))
aDict={}
for i,row in enumerate(bs):
 aDict[row[0]]=i
def sortSeq(fid):
 return aDict[fid]

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

sortSeq( !OID!)

Es dauert 1,5 Sekunden, um die Aufgabe für 10000 Datensätze abzuschließen. Das Original dauert etwas mehr als 2 Minuten

FelixIP
quelle
Ich glaube, die ersten vier Zeilen dieses Codes werden für jeden einzelnen Datensatz ausgeführt. Das darf nicht erlaubt sein, da der Layer für die gesamte Berechnung nur einmal sortiert werden muss. Verwenden Sie den Trick, den ich in meinem Beitrag zeige, oder zeigen Sie, dass die Ebene nur einmal gelesen wird, um die Sortierreihenfolge für den ersten Datensatz zu bestimmen.
Richard Fairhurst
@RichardFairhurst Ich habe meinen ursprünglichen Ausdruck an 10 Tausend Datensätzen getestet. Die Fertigstellung dauerte 2 Minuten und 06 Sekunden. Die Änderung führte zu einer Verbesserung von 5 Sekunden. Es scheint, dass die ersten Zeilen nicht bei jedem Datensatz wiederholt werden. Ja, der
Feldrechner
Testen Sie dieselbe Tabelle anhand meiner Berechnung. Wenn sie praktisch dieselbe Zeit für die Berechnung benötigen, akzeptiere ich Ihre Annahme, dass sie nur einmal verarbeitet wird. 2 Minuten und 6 Sekunden sind ziemlich langsam.
Richard Fairhurst
OK 1,5 Sekunden scheinen darauf hinzudeuten, dass die ersten 4 Zeilen nicht für jeden Datensatz verarbeitet werden. In jedem Fall ist das Wörterbuch der richtige Weg. Was tun Sie jedoch, wenn die Seq-Nummer nicht in jedem Datensatz eindeutig sein soll, wenn die Werte in den anderen Feldern gleich sind? Das würde ich mir für die zugehörige Tabelle in einer 1: M-Beziehung wünschen.
Richard Fairhurst
+1 @RichardFairhurst für Wörterbuch. Das Durchblättern der Liste war ein langsamer Teil meines Originals.
Um
6

Dies ist ein zweistufiger Prozess, weshalb der Feldrechner nicht gut dafür geeignet ist. Es ist besser, dies in einem eigenständigen Skript auszuführen. Dies kann jedoch im Feldrechner erfolgen, sofern Sie einen Trick verwenden. Sie müssen einen Cursor verwenden, um alle Werte aus einer sortierten Liste in ein globales Wörterbuch zu laden, jedoch nur während der Berechnung des ersten Datensatzes. Für alle anderen Datensätze müssen Sie die Wörterbucherstellung überspringen, um zu vermeiden, dass die gesamte Tabelle für jede Zeile ständig neu gelesen wird.

Die drei Feldwerte müssen in einem Tupel platziert werden, um als Schlüssel zu fungieren, der ordnungsgemäß sortiert wird. Ich gehe davon aus, dass alle 3-Feld-Kombinationswerte in der SamplePoint-Tabelle eindeutig sind, aber ich habe die ObjectID hinzugefügt, um sicherzustellen, dass sie eindeutig ist. Sie müssen den Pfad- und Shapefile-Namen in Zeile 8 angeben (oder ich könnte die Technik verwenden, die FelixIP verwendet, wenn die erste Ebene in der aktuellen Karte verwendet wird). Wenn Sie verschiedene Felder für einen Schlüssel verwenden möchten, müssen Sie die Feldliste in Zeile 10 ändern und sie mit den Eingabefeldern in Zeile 3 und Zeile 15 abgleichen.

#Pre-logic Script Code:
relateDict = {}
def autoIncrement(myYear, myMonth, myDay, OID): 
    global relateDict  
    # only populate the dictionary if it has no keys  
    if len(relateDict) == 0:  
        # Provide the path to the relate feature class/table  
        relateFC = r"C:\Users\OWNER\Documents\ArcGIS\SamplePoints.shp"  
        # create a field list with the relate fields in sort order  
        relateFieldsList = ["Year", "Month", "Day", "OID@"]  
        # process a da search cursor to transfer the data to the dictionary  
        relateList = sorted([(r[0:]) for r in arcpy.da.SearchCursor(relateFC, relateFieldsList)])
        for relateSort in range(0, len(relateList)):
            relateDict[relateList[relateSort]] = relateSort + 1
    return relateDict[(myYear,myMonth,myDay,OID)]    

#Expression:
autoIncrement(!Year!, !Month!, !Day!, !OBJECTID!)

Ich würde auch nicht empfehlen, die Feldnamen Jahr, Monat und Tag zu verwenden, da diese nur in Shapefiles funktionieren und in Geodatabases nicht zulässig sind. Eine Geodatabase ändert die Namen in Jahr_1, Monat_1, Tag_1, wenn Sie versuchen, sie der Feldliste in den Eigenschaften der Tabelle hinzuzufügen.

Wenn der Zweck dieser Tabelle darin besteht, sie mit einer anderen Tabelle / Feature-Class auf einem Mehrfeldschlüssel zu verknüpfen, sollten Sie das in meinem Blog erstellte Tool mit dem Namen " Mehrfachfeldschlüssel für Einzelfeldschlüssel" verwenden - zwei Ebenen basierend auf mehr als einer verknüpfen Feld

Richard Fairhurst
quelle
Wie geht es mit Duplikaten um?
FelixIP
Fügen Sie die OID zur Feldliste hinzu. Ich habe die OID zur Feldliste hinzugefügt, um sicherzustellen, dass sie eindeutig ist.
Richard Fairhurst
Wenn alternativ Duplikate vorhanden sind und der Benutzer möchte, dass alle Duplikate denselben SEQ-Wert haben, lassen Sie die ObjectID weg und verwenden Sie set () in der Liste, bevor Sie die for-Schleife ausführen und dem Wörterbuch hinzufügen.
Richard Fairhurst
+1 Danke @RichardFairhurst, ähnlich wie mein Versuch, in Arcpy zu schreiben, obwohl ich nicht wusste, dass Sie das meiste davon aus dem Feldrechner
herausrufen können
2

Ich hatte die gleiche Frage, aber für ein einfacheres Problem, basierend darauf, dass nur ein Feld sortiert werden musste. Ich war mit dem folgenden Skript erfolgreich:

# Pre-Logic Script Code:
# Specify that the target Map Document is the current one
mxd = arcpy.mapping.MapDocument("CURRENT")
# Specify that the target layer is the first layer in the table of 
# content
lr=arcpy.mapping.ListLayers(mxd)[0]

tbl=arcpy.da.TableToNumPyArray(lr,("fid","Name_of_sorted_Field"))
bs=sorted(tbl,key=lambda x: x[1])
aDict={}
for i,row in enumerate(bs):
 aDict[row[0]]=i
def sortSeq(fid):
 return aDict[fid]

---------------------------------------------------------------
# to run the code, the following goes in the expression window
sortSeq(!FID!)
user122347
quelle