使用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中,您应该可以做到这一点。表格如何排序?您可以将其读取为具有OID和排序字段的字典,对字典进行排序,使用OID和Value创建另一个字典,迭代排序后的第一个字典将值分配给第二个字典,然后通过分配第二个字典来游标... a有点混乱,但这就是我不使用ArcObjects就能想到的全部。
Michael Stimson

@ MichaelMiles-Stimson并不是一个坏主意,我可以将其加载到字典中以确定排序顺序,然后将这些值写到Seq中。
Midavalo

这就是我以前做过的,而且效果很好。我现在找不到我的代码;这是一次性的,所以可能在我的一张备份光盘上。
Michael Stimson

我一直很生气,这在ArcGIS中无法轻松完成。而在MapInfo中则是微不足道的。我遇到的最简单的方法是使用排序工具,但它会创建另一个必须加入的数据集。
Fezter

您的python语法可以完美运行,谢谢。我只是想知道是否可以从1开始而不是从0开始。如果可能的话,您可以给我提供它的代码。祝您度过一个愉快的周末弗雷德
弗雷德

Answers:


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分钟多一点的时间


我相信此代码的前四行正在针对每条记录运行。不允许这样做,因为对于整个计算,该图层只需要排序一次。考虑使用我在帖子中显示的技巧,或演示仅读取一次该层以确定仅第一条记录的记录排序顺序。
理查德·费尔赫斯特

@RichardFairhurst我在1万条记录中测试了我的原始表达,花了2分钟06秒完成,修改导致5秒的改进。似乎并不是每条记录都重复第一行。是的,字段计算器比脚本慢得多,但很方便
FelixIP 2016年

根据我的计算测试同一张表。如果他们花了几乎相同的时间进行计算,那么我将接受您的假设,即它仅被处理一次。2分6秒相当慢。
理查德·费尔赫斯特

OK 1.5秒似乎表明没有为每条记录处理前4行。无论如何,无论哪种情况,字典都是必经之路。但是,当其他字段中的值相同时,如果我希望Seq号在每条记录上都不唯一,该怎么办?那就是我想要的1:M关系中的相关表。
理查德·费尔赫斯特

+1 @RichardFairhurst字典。拖曳清单是我原著中的一个很慢的部分。并非唯一,这是OP的一大变化
FelixIP

6

这是一个两步过程,因此,字段计算器不太适合它。最好在独立脚本中运行它。但是,只要您使用技巧,就可以在现场计算器中完成。您确实需要使用游标从排序列表中将所有值加载到全局字典中,但是仅在计算第一条记录时才需要。对于所有其他记录,您必须跳过字典的创建,以避免不断重读每一行的整个表。

必须将三个字段值放在一个元组中,以作为将正确排序的键。我将假定所有3字段组合值在SamplePoint表中都是唯一的,但是我添加了ObjectID以确保其唯一。您必须在第8行中提供路径和shapefile名称(否则,我可以使用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,Month和Day字段名称,因为它们仅在shapefile中起作用,而在地理数据库中则不允许。如果您尝试将地理数据库的名称添加到表属性中的字段列表中,则会将其更改为Year_1,Month_1,Day_1。

如果此表的目的是将其与多字段键上的另一个表/功能类相关联,请考虑使用我在博客中创建的名为“ 多字段键到单字段键的工具”的工具-将基于多个的两层相关领域


它如何处理重复项?
FelixIP '16

将OID添加到字段列表中。我已将OID添加到字段列表中以确保它是唯一的。
理查德·费尔赫斯特

或者,如果存在重复项,并且用户希望所有重复项都具有相同的SEQ值,则在运行for循环并将其添加到字典之前,请省略ObjectID并在列表上使用set()。
理查德·费尔赫斯特

+1感谢@RichardFairhurst,与我尝试用arcpy编写代码的尝试几乎相同,尽管我没有意识到您可以从Field Calculator中调用大部分代码
Midavalo

2

我有一个相同的问题,但是有一个简单的问题,基于只对一个字段进行排序。我成功使用以下脚本:

# 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!)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.