Tính toán các số liên tiếp vào bảng được sắp xếp bằng ArcGIS Desktop?


11

Có cách nào để tính toán một trường được sắp xếp với các số liên tiếp không? Tôi đã thấy lớp tính năng Sắp xếp để tính toán trường ID tuần tự bằng Máy tính trường ArcGIS? phác thảo cách tính các số liên tiếp, nhưng điều này luôn được tính theo thứ tự FID, không phải theo thứ tự được sắp xếp.

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

Một ví dụ về những gì tôi đang cố gắng làm. Tôi đã sử dụng một loại sắp xếp nâng cao để sắp xếp theo năm, tháng, ngày và bây giờ muốn có các số liên tiếp trong Seqlĩnh vực này. Bạn sẽ thấy rằng OBJECTIDlĩnh vực của tôi không theo thứ tự, vì vậy đoạn mã trên sẽ không hoạt động.

nhập mô tả hình ảnh ở đây

Điều này có thể được thực hiện trong Máy tính trường hoặc sử dụng Con trỏ cập nhật trong Arcpy không?


Trong ArcObjects với ITableSort, bạn sẽ có thể làm điều đó .. không quá nhiều trong python. Bảng được sắp xếp như thế nào? bạn có thể đọc nó lên một từ điển với trường OID và sắp xếp, sắp xếp từ điển, tạo một từ điển khác với OID và Value, lặp lại từ điển đầu tiên được sắp xếp để gán giá trị cho thứ hai sau đó con trỏ thông qua việc gán với từ điển thứ hai ... a một chút lẩm bẩm xung quanh nhưng đó là tất cả những gì tôi có thể nghĩ đến mà không cần sử dụng ArcObjects.
Michael Promotionson

@ MichaelMiles - Kích thích đó không phải là một ý tưởng tồi, tôi có thể tải nó vào từ điển để xác định thứ tự sắp xếp sau đó viết các giá trị đó ra Seq.
Midavalo

Đó là cách tôi đã làm nó trước đây và nó hoạt động tốt. Tôi không thể tìm thấy mã của mình ngay bây giờ; Đó là một lần nên có lẽ nó nằm trên một trong những đĩa dự phòng của tôi ... Nếu tôi gặp nó tôi sẽ đăng dưới dạng câu trả lời - miễn là chưa có câu trả lời hay cho câu hỏi này.
Michael Promotionson

Tôi luôn cảm thấy khó chịu vì điều này không thể thực hiện dễ dàng trong ArcGIS. Trong khi đó, nó không quan trọng trong MapInfo. Cách dễ nhất mà tôi đã gặp là sử dụng Công cụ Sắp xếp nhưng nó tạo ra một bộ dữ liệu khác mà bạn phải tham gia lại.
Fezter

Cú pháp python của bạn hoạt động hoàn hảo, cảm ơn vì điều đó. Tôi chỉ tự hỏi liệu có thể bắt đầu hàng đầu tiên bằng 1 chứ không phải 0. Nếu có thể, bạn có thể cho tôi mã cho nó. Chúc một tuần tốt lành Fred
Fred

Câu trả lời:


13

"Giải pháp" với 2 trường được sắp xếp (tăng dần):

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

nhập mô tả hình ảnh ở đây

PHIÊN BẢN CẬP NHẬT:

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

mất 1,5 giây để hoàn thành nhiệm vụ trên 10000 hồ sơ. Bản gốc mất hơn 2 phút


Tôi tin rằng bốn dòng đầu tiên của mã này đang được chạy cho mỗi bản ghi. Điều đó không được phép, vì lớp chỉ cần được sắp xếp một lần cho toàn bộ tính toán. Xem xét sử dụng thủ thuật tôi hiển thị trong bài đăng của mình hoặc chứng minh rằng lớp chỉ được đọc một lần để xác định thứ tự sắp xếp bản ghi cho bản ghi đầu tiên.
Richard Fairhurst

@RichardFairhurst Tôi đã kiểm tra biểu thức ban đầu của mình trên 10 nghìn hồ sơ, phải mất 2 phút 06 giây để hoàn thành, sửa đổi dẫn đến cải thiện 5 giây. Dường như những dòng đầu tiên không lặp lại trên mỗi bản ghi. Có máy tính trường chậm hơn nhiều so với tập lệnh, mặc dù tiện lợi
FelixIP

Kiểm tra cùng bảng với tính toán của tôi. Nếu họ mất gần như cùng một thời gian để thực hiện tính toán thì tôi sẽ chấp nhận giả định của bạn rằng nó chỉ được xử lý một lần. 2 phút và 6 giây là khá chậm.
Richard Fairhurst

OK 1,5 giây dường như chỉ ra rằng 4 dòng đầu tiên không được xử lý cho mỗi bản ghi. Dù sao, từ điển là cách để đi trong cả hai trường hợp. Tuy nhiên, bạn sẽ làm gì khi tôi muốn số Seq không phải là duy nhất trên mỗi bản ghi khi các giá trị trong các trường khác giống nhau? Đó sẽ là những gì tôi muốn cho bảng liên quan trong mối quan hệ 1: M.
Richard Fairhurst

+1 @RichardFairhurst cho từ điển. Xáo trộn thông qua danh sách là một phần chậm trong bản gốc của tôi. Không phải là duy nhất, đó là một biến thể lớn của OP
FelixIP

6

Đây là một quá trình gồm hai bước và kết quả là Máy tính Trường không phù hợp với nó. Nó là tốt hơn để chạy này trong một kịch bản độc lập. Tuy nhiên, nó có thể được thực hiện trong máy tính trường, miễn là bạn sử dụng một mẹo. Bạn cần phải sử dụng một con trỏ để tải tất cả các giá trị vào một từ điển toàn cầu từ một danh sách được sắp xếp, nhưng chỉ trong quá trình tính toán của bản ghi đầu tiên. Đối với tất cả các bản ghi khác, bạn phải bỏ qua việc tạo từ điển để tránh liên tục đọc lại toàn bộ bảng cho mỗi hàng.

Ba giá trị trường phải được đặt trong một tuple để hoạt động như một khóa sẽ sắp xếp đúng. Tôi sẽ giả sử tất cả các giá trị kết hợp 3 trường là duy nhất trong bảng SamplePoint, nhưng tôi đã thêm ObjectID để đảm bảo nó là duy nhất. Bạn phải cung cấp đường dẫn và tên shapefile trong dòng 8 (hoặc tôi có thể sử dụng kỹ thuật mà FelixIP sử dụng khi sử dụng lớp đầu tiên trong bản đồ hiện tại). Nếu bạn muốn sử dụng các trường khác nhau cho một khóa, bạn phải thay đổi danh sách trường trong dòng 10 và khớp chúng với các trường đầu vào ở dòng 3 và dòng 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!)

Tôi cũng không khuyến nghị sử dụng tên trường của Năm, Tháng và Ngày, vì những tên này chỉ hoạt động trong shapefile và không được phép trong cơ sở dữ liệu địa lý. Cơ sở dữ liệu địa lý sẽ thay đổi tên thành Năm_1, Tháng_1, Ngày_1 nếu bạn cố thêm chúng vào danh sách trường trong các thuộc tính của bảng.

Nếu mục đích của bảng này là liên kết nó với một lớp bảng / tính năng khác trên khóa đa trường, hãy xem xét sử dụng công cụ tôi đã tạo trong Blog của mình có tên Khóa nhiều trường với Công cụ khóa trường đơn - Liên kết hai lớp dựa trên nhiều lớp Cánh đồng


Làm thế nào để nó xử lý trùng lặp?
FelixIP

Thêm OID vào danh sách trường. Tôi đã thêm OID vào danh sách trường để đảm bảo nó là duy nhất.
Richard Fairhurst

Ngoài ra, nếu có các bản sao và người dùng muốn tất cả các bản sao có cùng giá trị SEQ thì hãy bỏ ObjectID và sử dụng set () trong danh sách trước khi chạy vòng lặp for và thêm nó vào từ điển.
Richard Fairhurst

+1 Cảm ơn @RichardFairhurst, giống như nỗ lực của tôi để viết trong Arcpy, mặc dù tôi không nhận ra rằng bạn có thể gọi hầu hết số đó từ trong Máy tính Trường
Midavalo

2

Tôi có cùng một câu hỏi nhưng đối với một vấn đề đơn giản hơn, dựa trên việc chỉ có một Trường để sắp xếp. Tôi đã thành công với kịch bản sau:

# 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!)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.