ArcGIS Desktopを使用して連続番号をソート済みテーブルに計算しますか?


11

連番でソートされたフィールドを計算する方法はありますか?ArcGIS Field Calculatorを使用してシーケンシャルIDフィールドを計算するソートフィーチャクラスを見ましたか?連番の計算方法の概要を説明しますが、これは常にソート順ではなくFID順で計算されます。

#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()

私がやろうとしていることの。年、月、日でソートするために高度なソートを使用しましたが、Seqフィールドに連番を付けたいと考えています。あなたは私のOBJECTIDフィールドが整頓されていないことがわかりますので、上記のコードは動作しません。

ここに画像の説明を入力してください

これは、フィールド計算機またはarcpyの更新カーソルを使用して実行できますか?


ITableSortを使用したArcObjectsでは、それを行うことができるはずです。Pythonではそれほどではありません。テーブルはどのようにソートされますか?OIDとソートフィールドを持つ辞書までそれを読み、辞書をソートし、OIDと値を持つ別の辞書を作成し、ソートされた最初の辞書を繰り返して値を2番目に割り当て、カーソルを2番目の辞書に割り当てて...少しいじくり回しますが、ArcObjectsを使用せずに考えることができます。
マイケルスティムソン

@ MichaelMiles-Stimsonは悪い考えではありません。おそらくそれを辞書にロードしてソート順を決定し、それらの値をSeqに書き込むことができます。
ミダバロ

それは私が前にそれをやった方法であり、それはうまく機能しています。現在、コードが見つかりません。これは1回限りだったので、おそらく私のバックアップディスクの1つにあります。
マイケルスティムソン

これはArcGISで簡単に行えないことにいつも悩まされていました。一方、MapInfoでは簡単です。私が出くわした最も簡単な方法は、並べ替えツールを使用することですが、それにより、再度結合する必要がある別のデータセットが作成されます。
フェスター

あなたのpython構文は完璧に動作します、そのおかげです。最初の行を0ではなく1で開始することが可能かどうか疑問に思っています。可能であれば、そのコードを教えてください。良い週末を
フレッド

回答:


13

2つのソートされたフィールドを持つ「ソリューション」(昇順):

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! )

ここに画像の説明を入力してください

更新版:

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!)

10000レコードでタスクを完了するには1.5秒かかります。オリジナルには2分以上かかります


このコードの最初の4行は、すべてのレコードに対して実行されていると思います。レイヤーは計算全体で一度だけソートされる必要があるため、これは許可されてはなりません。投稿で示したトリックの使用を検討するか、最初のレコードのみのレコードの並べ替え順序を決定するために、レイヤーが一度だけ読み取られることを示します。
リチャードフェアハースト

@RichardFairhurst私は元の表現を1万件のレコードでテストしました。完了するのに2分6秒かかり、変更の結果は5秒改善しました。すべてのレコードで最初の行が繰り返されていないようです。はいフィールドの計算は、はるかに遅いスクリプトよりも、便利けれどもある
FelixIP

私の計算に対して同じテーブルをテストします。彼らが計算を行うのに実質的に同じ時間がかかる場合、それは一度だけ処理されるというあなたの仮定を受け入れます。2分6秒はかなり遅いです。
リチャードフェアハースト

OK 1.5秒は、最初の4行が各レコードで処理されていないことを示しているように見えます。とにかく、辞書はどちらの場合でも行く方法です。ただし、他のフィールドの値が同じ場合に各レコードでSeq番号を一意にしたくない場合はどうしますか?それは、1:M関係の関連テーブルに必要なものです。
リチャードフェアハースト

+1 @RichardFairhurst for dictionary。リストをシャッフルすることは、私のオリジナルでは遅い部分でした。それはOPの大きな変化であるユニークではないと再
FelixIP

6

これは2段階のプロセスであるため、フィールド計算機はそれに適していません。スタンドアロンスクリプトでこれを実行することをお勧めします。ただし、トリックを使用すれば、フィールド計算機で実行できます。カーソルを使用して、ソートされたリストからグローバル辞書にすべての値をロードする必要がありますが、最初のレコードの計算中のみです。他のすべてのレコードについては、辞書の作成をスキップして、各行のテーブル全体を絶えず再読み取りしないようにする必要があります。

適切にソートされるキーとして機能するには、3つのフィールド値をタプルに配置する必要があります。SamplePointテーブルではすべての3フィールドの組み合わせの値が一意であると仮定しますが、一意になるようにObjectIDを追加しました。8行目にパスとシェープファイル名を指定する必要があります(または、現在のマップの最初のレイヤーが使用される場所でFelixIPが使用する手法を使用できます)。キーに異なるフィールドを使用する場合は、10行目のフィールドリストを変更し、3行目と15行目の入力フィールドと一致させる必要があります。

#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!)

また、年、月、日のフィールド名を使用することはお勧めしません。これらはシェープファイルでのみ機能し、ジオデータベースでは許可されないためです。テーブルのプロパティのフィールドリストに名前を追加しようとすると、ジオデータベースは名前をYear_1、Month_1、Day_1に変更します。

このテーブルの目的が、マルチフィールドキー上の別のテーブル/機能クラスに関連付けることである場合、ブログで作成したマルチフィールドキーからシングルフィールドキーツールという名前のツールを使用することを検討してください。フィールド


重複をどのように処理しますか?
FelixIP

OIDをフィールドリストに追加します。OIDをフィールドリストに追加して、一意であることを確認しました。
リチャードフェアハースト

あるいは、重複があり、ユーザーが重複のすべてに同じSEQ値を持たせたい場合は、forループを実行して辞書に追加する前に、ObjectIDを省略し、リストでset()を使用します。
リチャードフェアハースト

私はあなたがフィールド電卓の中から、そのほとんどを呼び出すことができます実現しなかったものの、1人のおかげで、arcpyでの書き込みに私の試みとほぼ同じ、@RichardFairhurst
Midavalo

2

私は同じ質問をしましたが、ソートするフィールドが1つしかないことに基づいたより単純な問題です。次のスクリプトで成功しました。

# 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!)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.