Menghitung angka berurutan ke dalam tabel yang diurutkan menggunakan ArcGIS Desktop?

11

Apakah ada cara untuk menghitung bidang yang diurutkan dengan nomor urut? Saya telah melihat fitur Sorting class untuk menghitung bidang ID berurutan menggunakan ArcGIS Field Calculator? yang menguraikan cara menghitung angka berurutan, tetapi ini selalu dihitung pada urutan FID, bukan pada urutan.

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

Sebuah contoh dari apa yang saya coba lakukan. Saya telah menggunakan pengurutan tingkat lanjut untuk mengurutkan berdasarkan tahun, bulan, hari, dan sekarang ingin memiliki nomor urut di Seqlapangan. Anda akan melihat bahwa OBJECTIDbidang saya tidak berurutan, sehingga kode di atas tidak akan berfungsi.

masukkan deskripsi gambar di sini

Apakah ini bisa dilakukan di Kalkulator Bidang atau menggunakan Kursor Pembaruan di arcpy?

Midavalo
sumber
Dalam ArcObjects dengan ITableSort Anda harus dapat melakukannya .. tidak terlalu banyak dengan python. Bagaimana tabel diurutkan? Anda bisa membacanya ke kamus dengan OID dan mengurutkan bidang, mengurutkan kamus, membuat kamus lain dengan OID dan Nilai, mengulangi kamus pertama yang diurutkan untuk menetapkan nilai ke yang kedua lalu kursor melalui penugasan dengan kamus kedua ... a sedikit mucking sekitar tapi itu yang bisa saya pikirkan tanpa menggunakan ArcObjects.
Michael Stimson
@ MichaelMiles-Stimson itu bukan ide yang buruk, saya mungkin bisa memuatnya ke dalam kamus untuk menentukan susunan urutan kemudian menulis nilai-nilai itu ke Seq.
Midavalo
Begitulah cara saya melakukannya sebelumnya dan bekerja dengan baik. Saya tidak dapat menemukan kode saya sekarang; Itu hanya satu kali jadi mungkin pada salah satu cakram cadangan saya ... Jika saya temui saya akan memposting sebagai jawaban - asalkan belum ada jawaban yang baik untuk pertanyaan ini.
Michael Stimson
Saya selalu kesal karena ini tidak dapat dilakukan dengan mudah di ArcGIS. Padahal, itu sepele di MapInfo. Cara termudah yang saya temui adalah menggunakan Alat Sortir tetapi itu membuat dataset lain yang harus Anda gabungkan kembali.
Fezter
Sintaksis python Anda berfungsi dengan baik, terima kasih untuk itu. Saya hanya ingin tahu apakah mungkin untuk memulai baris pertama dengan 1 daripada 0. Jika mungkin dapat Anda berikan saya kode untuk itu. Semoga akhir pekan Anda menyenangkan Fred
Fred

Jawaban:

13

"Solusi" dengan 2 bidang yang diurutkan (menaik):

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

masukkan deskripsi gambar di sini

VERSI TERBARU:

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

dibutuhkan 1,5 detik untuk menyelesaikan tugas pada 10.000 catatan. Asli membutuhkan waktu lebih dari 2 menit

FelixIP
sumber
Saya percaya empat baris pertama dari kode ini sedang dijalankan untuk setiap record. Itu tidak boleh diizinkan, karena layer hanya perlu disortir sekali untuk seluruh perhitungan. Pertimbangkan untuk menggunakan trik yang saya perlihatkan di posting saya atau menunjukkan bahwa layer hanya sedang dibaca sekali untuk menentukan urutan pengurutan catatan untuk hanya catatan pertama.
Richard Fairhurst
@RichardFairhurst Saya menguji ekspresi asli saya pada 10 ribu catatan, butuh 2 menit 06 detik untuk menyelesaikan, modifikasi menghasilkan peningkatan 5 detik. Tampaknya baris pertama tidak diulang pada setiap rekaman. Ya, kalkulator lapangan jauh lebih lambat daripada skrip, mudah
FelixIP
Uji tabel yang sama dengan perhitungan saya. Jika mereka mengambil waktu yang hampir sama untuk melakukan perhitungan maka saya akan menerima asumsi Anda bahwa itu hanya sedang diproses sekali. 2 mnt dan 6 detik cukup lambat.
Richard Fairhurst
OK 1,5 detik sepertinya mengindikasikan bahwa 4 baris pertama tidak sedang diproses untuk setiap record. Bagaimanapun, kamus adalah cara untuk memilih dalam kedua kasus. Namun, apa yang Anda lakukan ketika saya ingin nomor Seq tidak menjadi unik pada setiap catatan ketika nilai di bidang lain sama? Itu akan menjadi apa yang saya inginkan untuk tabel terkait dalam hubungan 1: M.
Richard Fairhurst
+1 @RichardFairhurst untuk kamus. Mengaduk-aduk daftar adalah bagian lambat dari aslinya. Kembali tidak menjadi unik itu adalah variasi besar OP
FelixIP
6

Ini adalah proses dua langkah, dan sebagai hasilnya, Kalkulator Lapangan tidak cocok untuk itu. Lebih baik menjalankan ini dalam skrip mandiri. Namun, itu bisa dilakukan di bidang kalkulator, asalkan Anda menggunakan trik. Anda perlu menggunakan kursor untuk memuat semua nilai ke kamus global dari daftar yang diurutkan, tetapi hanya selama perhitungan catatan pertama. Untuk semua catatan lain Anda harus melewati pembuatan kamus untuk menghindari membaca ulang seluruh tabel untuk setiap baris secara konstan.

Tiga nilai bidang harus ditempatkan di tuple untuk bertindak sebagai kunci yang akan mengurutkan dengan benar. Saya akan menganggap semua nilai kombinasi 3-bidang unik di tabel SamplePoint, tetapi saya menambahkan ObjectID untuk memastikannya unik. Anda harus memberikan path dan nama shapefile di baris 8 (atau saya bisa menggunakan teknik yang FelixIP gunakan di mana lapisan pertama di peta saat ini digunakan). Jika Anda ingin menggunakan bidang yang berbeda untuk kunci Anda harus mengubah daftar bidang di baris 10 dan mencocokkannya dengan bidang input di baris 3 dan baris 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!)

Saya juga tidak akan merekomendasikan menggunakan nama bidang Tahun, Bulan dan Hari, karena hanya berfungsi di shapefile dan tidak diizinkan di geodatabases. Database geodat akan mengubah nama menjadi Year_1, Month_1, Day_1 jika Anda mencoba menambahkannya ke daftar bidang di properti tabel.

Jika tujuan tabel ini adalah untuk mengaitkannya dengan tabel lain / kelas fitur pada kunci multi-bidang, pertimbangkan untuk menggunakan alat yang saya buat di Blog saya bernama Multiple Field Key ke Single Tool Key Field - Hubungkan Dua Layers Berdasarkan Lebih dari Satu Bidang

Richard Fairhurst
sumber
Bagaimana cara menangani duplikat?
FelixIP
Tambahkan OID ke daftar bidang. Saya telah menambahkan OID ke daftar bidang untuk memastikannya unik.
Richard Fairhurst
Atau jika ada duplikat dan pengguna ingin semua duplikat memiliki nilai SEQ yang sama kemudian tinggalkan ObjectID dan gunakan set () pada daftar sebelum menjalankan loop for dan menambahkannya ke kamus.
Richard Fairhurst
+1 Terima kasih @RichardFairhurst, sama seperti usaha saya untuk menulis di arcpy, walaupun saya tidak sadar Anda bisa memanggil sebagian besar dari dalam Field Calculator
Midavalo
2

Saya memiliki pertanyaan yang sama tetapi untuk masalah yang lebih sederhana, berdasarkan hanya memiliki satu Field untuk diurutkan. Saya berhasil dengan skrip berikut:

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