I know I can do it with Dissolve, but the issue with Dissolve is that it creates a separate layer and I know I can do this a script but I need to in Model Builder. I need the function to merge feature class based on two attributes. Can this be down with Calculate value in model builder? I have tried the following, but it never seems to finish the process. The model function does seem to work, I check the feature class and the feature class features are merged. I have to manually hit stop.
Expression:
f(fc)
Code block:
import sys, arcpy, os
from arcpy import env
from arcpy import da
from itertools import groupby
from operator import itemgetter
from functools import reduce
fc = r"C:/TEMP/FEMA.gdb/FEMA_TempLyrs"
def f(fc):
case_fields = ["FLD_ZONE",'ZONE_SUBTY'] # field(s) to group records for merging
sort_field, sort_order = "OBJECTID", "ASC"
shape_field = "SHAPE@"
fields = case_fields + [sort_field, shape_field]
sql_orderby = "ORDER BY {}, {} {}".format(", ".join(case_fields), sort_field, sort_order)
with da.UpdateCursor(fc, fields, sql_clause=(None, sql_orderby)) as cur:
case_func = itemgetter(*range(len(case_fields)))
merged_polys = {
key:reduce(arcpy.Geometry.union, (row[-1] for row in group))
for key, group
in groupby(cur, case_func)
}
cur.reset()
for key, group in groupby(cur, case_func):
row = next(group)
cur.updateRow(row[:-1] + [merged_polys[key]])
for row in group:
cur.deleteRow()
del cur
return fc
I would look at separating your operations. If you are building a dictionary in the first part, do that in a SearchCursor. Drop the cur.reset(). Then with an UpdateCursor, iterate over the key, group dictionary and do your update.
Thanks for the reply, I guess I am not understand how to put the code/model together to work.
Is there another way that this can be accomplished?
This is untested and to just show you the splitting of two operations that you are doing that I think would replace the reset(). Probably need an iterator in the each cursor somewhere? That's something you'll have to test and see.
merged_polys = None
with da.SearchCursor(fc, fields, sql_clause=(None, sql_orderby)) as cur:
case_func = itemgetter(*range(len(case_fields)))
merged_polys = {
key:reduce(arcpy.Geometry.union, (r[-1] for r in group))
for key, group
in groupby(row, case_func)
}
with da.UpdateCursor(fc, fields, sql_clause=(None, sql_orderby)) as uCur:
for key, group in groupby(uCur, case_func):
row = next(group)
uCur.updateRow(row[:-1] + [merged_polys[key]])
for row in group:
uCur.deleteRow()
Alternative is add print statements to see where it is getting stuck in the loop and go from there.
Sorry for the late response. I wasn't sure if you meat separate the two into two separate calculate values, how I was suppose to call the first calculate value to the second calculate value. So I figured why the model didn't stop, FLD_ZONE had some empty attributes.
I tried the following it runs but nothing is merged, no errors.
fc = r"C:\Temp\FEMA.gdb\FEMA_TempLyrs
def f(fc):
case_fields = ["FLD_ZONE",'ZONE_SUBTY'] # field(s) to group records for merging
sort_field, sort_order = "OBJECTID", "ASC"
shape_field = "SHAPE@"
fields = case_fields + [sort_field, shape_field]
sql_orderby = "ORDER BY {}, {} {}".format(", ".join(case_fields), sort_field, sort_order)
with da.UpdateCursor(fc, fields, sql_clause=(None, sql_orderby)) as cur:
for row in cur:
print (row)
if row[0] == None:
case_func = itemgetter(*range(len(case_fields)))
merged_polys = {
key:reduce(arcpy.Geometry.union, (row[-1] for row in group))
for key, group
in groupby(cur, case_func)
}
cur.reset()
for key, group in groupby(cur, case_func):
row = next(group)
cur.updateRow(row[:-1] + [merged_polys[key]])
for row in group:
cur.deleteRow()
del cur
return fc
I also tried separating the operations like you stated but nothing gets merged, with error.
Error:
ERROR 000539: Traceback (most recent call last):
File "<expression>", line 1, in <module>
File "<string>", line 38, in fc1
TypeError: 'NoneType' object is not subscriptable
import sys, arcpy, os
from arcpy import env
from arcpy import da
from itertools import groupby
from operator import itemgetter
from functools import reduce
fc = r"C:\Temp\FEMA.gdb\FEMA_TempLyrs"
def f(fc):
case_fields = ["FLD_ZONE",'ZONE_SUBTY'] # field(s) to group records for merging
sort_field, sort_order = "OBJECTID", "ASC"
shape_field = "SHAPE@"
fields = case_fields + [sort_field, shape_field]
sql_orderby = "ORDER BY {}, {} {}".format(", ".join(case_fields), sort_field, sort_order)
merged_polys = None
with da.SearchCursor(fc, fields, sql_clause=(None, sql_orderby)) as cur:
case_func = itemgetter(*range(len(case_fields)))
for row in cur:
print (row)
if row[0] == None:
merged_polys = {
key:reduce(arcpy.Geometry.union, (row[-1] for row in group))
for key, group
in groupby(cur, case_func)
}
else:
pass
del cur
with da.UpdateCursor(fc, fields, sql_clause=(None, sql_orderby)) as uCur:
for key, group in groupby(uCur, case_func):
row = next(group)
uCur.updateRow(row[:-1] + [merged_polys[key]])
for row in group:
uCur.deleteRow()
return fc