<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Optimizing UpdateCursor Script in Python Questions</title>
    <link>https://community.esri.com/t5/python-questions/optimizing-updatecursor-script/m-p/1366607#M69543</link>
    <description>&lt;P&gt;I'm not going to touch the logic you have that calculates offset. You'll need to review that on your own.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;pt_tbl = "ArcPRO_MasterQuery_EXT_pt"

pt_tbl_fields = ["DISTANCE", "DESCRIPTION_1", "DESCRIPTION_2", "DESCRIPTION_3", "Offset"]
trail_num_sec = ["11-1", "11-2"]
comma_sep_str = ",".join([f"'{i}'" for i in trail_num_sec])
expression = f"NUM_SEC in({comma_sep_str})"

oor = {}
oo  = {}
with arcpy.da.UpdateCursor(pt_tbl, pt_tbl_fields, expression) as u_cursor:
    for distance, desc_1, desc_2, desc_3, offset in u_cursor:
        oo[distance] = oo.get(distance, 0) + 1

        if "RHS" in [desc_1, desc_2, desc_3]:
            oor[distance] = oor.get(distance, 0) + 1

            offset = (oo[distance] - 1) * -1

        elif distance in oor:
            offset = (oo[distance] - (oor[distance]+1))
        else:
            offset (oo[distance] - 1)

        u_cursor.updateRow([distance, desc_1, desc_2, desc_3, offset])

print("Point Table Offsets Calculated")&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
    <pubDate>Thu, 04 Jan 2024 23:18:29 GMT</pubDate>
    <dc:creator>BlakeTerhune</dc:creator>
    <dc:date>2024-01-04T23:18:29Z</dc:date>
    <item>
      <title>Optimizing UpdateCursor Script</title>
      <link>https://community.esri.com/t5/python-questions/optimizing-updatecursor-script/m-p/1366291#M69536</link>
      <description>&lt;P&gt;Hello everyone,&lt;/P&gt;&lt;P&gt;I'm building a script to calculate offset values for linearly referenced data based on how many times distance values occur in a dataset. This is the script I've come up with and it works how I'd like it to, though once applied to the 6,000+ piece dataset it takes hours to complete.&amp;nbsp;&lt;/P&gt;&lt;P&gt;Any thoughts on how I might be able to speed it up?&lt;/P&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;DIV class=""&gt;&lt;DIV&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;LI-CODE lang="python"&gt;#pt table
pt_tbl = 'ArcPRO_MasterQuery_EXT_pt'

with arcpy.da.SearchCursor(pt_tbl, "NUM_SEC") as cursor2:
    traillist = []
    tns = set(cursor2)
    for thing in tns:
        for d in thing:
            traillist.append(d)
    traillistsortpt = sorted(traillist)

print("Calculating Point Table Offsets...")

traillistsortpt = ["11-1", "11-2"]

i = 0
for num in traillistsortpt:
    arcpy.management.SelectLayerByAttribute(pt_tbl, "NEW_SELECTION", "NUM_SEC = '%s'" %(num))
    
    oor = {}
    oo  = {}
    
    with arcpy.da.UpdateCursor(pt_tbl, ["OID@", "DISTANCE", "DESCRIPTION_1", "DESCRIPTION_2", "DESCRIPTION_3", "Offset"]) as cursor1:
        for row in cursor1:
            distance_value = row[1]
            oo[distance_value] = oo.get(distance_value, 0) +1
            
            
            if "RHS" in str(row[2]) or "RHS" in str(row[3]) or "RHS" in str(row[4]):
                oor[distance_value] = oor.get(distance_value, 0) + 1

                orh = (oo[distance_value] - 1) * -1
                row[5] = orh

            elif row[1] in oor:
                o = (oo[distance_value] - (oor[distance_value]+1))
                row[5] = o
            else:
                o = (oo[distance_value] - 1)
                row[5] = o
            
            cursor1.updateRow(row)
            

    i+=1
    print(i, " of ", len(traillistsortpt))

arcpy.management.SelectLayerByAttribute(pt_tbl, "CLEAR_SELECTION")
print("Point Table Offsets Calculated")        &lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Thu, 04 Jan 2024 17:26:28 GMT</pubDate>
      <guid>https://community.esri.com/t5/python-questions/optimizing-updatecursor-script/m-p/1366291#M69536</guid>
      <dc:creator>AlexanderDyer</dc:creator>
      <dc:date>2024-01-04T17:26:28Z</dc:date>
    </item>
    <item>
      <title>Re: Optimizing UpdateCursor Script</title>
      <link>https://community.esri.com/t5/python-questions/optimizing-updatecursor-script/m-p/1366386#M69537</link>
      <description>&lt;P&gt;I won't pretend to know what the script is doing but instead of iterating over your list of numbers, can you just run the select by attributes based on the list?&amp;nbsp; Also are you sure the selection is being honoured as you just seem to reference the same table in the cursor rather than:&lt;/P&gt;&lt;LI-CODE lang="python"&gt;selected_features = arcpy.SelectlayerByAttribute(pt_tbl, ...)
with arcpy.da.UpdateCursor(selected_features, fields) as cursor:&lt;/LI-CODE&gt;&lt;P&gt;As an aside I'd recommend some code comments and more understandable variable names if someone ever has to read or edit your code in the future.&lt;/P&gt;&lt;LI-CODE lang="c"&gt;arcpy.management.SelectLayerByAttribute(pt_tbl, "NEW_SELECTION", "NUM_SEC IN '%s'" %(traillistsortpt))&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Thu, 04 Jan 2024 17:27:11 GMT</pubDate>
      <guid>https://community.esri.com/t5/python-questions/optimizing-updatecursor-script/m-p/1366386#M69537</guid>
      <dc:creator>DavidPike</dc:creator>
      <dc:date>2024-01-04T17:27:11Z</dc:date>
    </item>
    <item>
      <title>Re: Optimizing UpdateCursor Script</title>
      <link>https://community.esri.com/t5/python-questions/optimizing-updatecursor-script/m-p/1366502#M69539</link>
      <description>&lt;P&gt;I only have time to comment on the SearchCursor structure, the current code can be condensed down to two lines:&lt;/P&gt;&lt;LI-CODE lang="python"&gt;with arcpy.da.SearchCursor(pt_tbl, "NUM_SEC") as cursor2:
    traillistsortpt = sorted(set(row[0] for row in cursor2))    &lt;/LI-CODE&gt;</description>
      <pubDate>Thu, 04 Jan 2024 20:59:41 GMT</pubDate>
      <guid>https://community.esri.com/t5/python-questions/optimizing-updatecursor-script/m-p/1366502#M69539</guid>
      <dc:creator>JoshuaBixby</dc:creator>
      <dc:date>2024-01-04T20:59:41Z</dc:date>
    </item>
    <item>
      <title>Re: Optimizing UpdateCursor Script</title>
      <link>https://community.esri.com/t5/python-questions/optimizing-updatecursor-script/m-p/1366511#M69540</link>
      <description>&lt;P&gt;When you say " 6,000+ piece dataset", do you mean the &lt;SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;STRONG&gt;traillistsortp&lt;/STRONG&gt;t&lt;/FONT&gt;&lt;/SPAN&gt; list is 6,000+ items or the &lt;STRONG&gt;&lt;FONT face="courier new,courier"&gt;pt_tbl&lt;/FONT&gt;&lt;/STRONG&gt; layer has 6,000+ records?&lt;/P&gt;</description>
      <pubDate>Thu, 04 Jan 2024 21:09:06 GMT</pubDate>
      <guid>https://community.esri.com/t5/python-questions/optimizing-updatecursor-script/m-p/1366511#M69540</guid>
      <dc:creator>JoshuaBixby</dc:creator>
      <dc:date>2024-01-04T21:09:06Z</dc:date>
    </item>
    <item>
      <title>Re: Optimizing UpdateCursor Script</title>
      <link>https://community.esri.com/t5/python-questions/optimizing-updatecursor-script/m-p/1366601#M69542</link>
      <description>&lt;OL&gt;&lt;LI&gt;As&amp;nbsp;&lt;a href="https://community.esri.com/t5/user/viewprofilepage/user-id/167692"&gt;@DavidPike&lt;/a&gt;&amp;nbsp;mentioned, your variable naming makes your code unnecessarily hard to follow.&lt;/LI&gt;&lt;LI&gt;The SearchCursor portion that builds the traillistsortpt list is immediately overwritten with hardcoded values on line 14. Why?&lt;/LI&gt;&lt;LI&gt;You can use &lt;A href="https://docs.python.org/3.9/library/functions.html#enumerate" target="_self"&gt;enumerate()&lt;/A&gt; to count iterations of a thing instead of counting it yourself with &lt;FONT face="courier new,courier"&gt;i&lt;/FONT&gt;&lt;/LI&gt;&lt;LI&gt;At the very least, use the &lt;A href="https://www.w3schools.com/python/ref_string_format.asp" target="_self"&gt;string format() method&lt;/A&gt; instead of the old %s operator. If you're working in ArcGIS Pro (Python 3), use the &lt;A href="https://docs.python.org/3.9/tutorial/inputoutput.html#tut-f-strings" target="_self"&gt;f-string&lt;/A&gt;&lt;/LI&gt;&lt;LI&gt;Declaring cursors outside the loop is more performant because it won't get recreated with every iteration of the loop.&lt;/LI&gt;&lt;LI&gt;&lt;A href="https://www.scaler.com/topics/python/packing-and-unpacking-in-python/" target="_self"&gt;Sequence unpacking&lt;/A&gt; can sometimes be a convenient way to name the cursor's individual values instead of referring to them by their row index. It gets a bit much if you have more than a handful of fields though, in which case you could &lt;A href="https://arcpy.wordpress.com/2012/07/12/getting-arcpy-da-rows-back-as-dictionaries/" target="_self"&gt;make each row a dictionary&lt;/A&gt; with field names.&lt;/LI&gt;&lt;LI&gt;You should utilize the&lt;A href="https://pro.arcgis.com/en/pro-app/3.1/arcpy/data-access/updatecursor-class.htm" target="_self"&gt; where_clause parameter of the UpdateCursor&lt;/A&gt; instead of making a selection.&lt;/LI&gt;&lt;LI&gt;Your logic for setting the Offset field value (row[5]) seems flawed. You're checking for a value in &lt;FONT face="courier new,courier"&gt;oor&lt;/FONT&gt; before you put the value in &lt;FONT face="courier new,courier"&gt;oor&lt;/FONT&gt;.&lt;/LI&gt;&lt;/OL&gt;</description>
      <pubDate>Thu, 04 Jan 2024 23:01:13 GMT</pubDate>
      <guid>https://community.esri.com/t5/python-questions/optimizing-updatecursor-script/m-p/1366601#M69542</guid>
      <dc:creator>BlakeTerhune</dc:creator>
      <dc:date>2024-01-04T23:01:13Z</dc:date>
    </item>
    <item>
      <title>Re: Optimizing UpdateCursor Script</title>
      <link>https://community.esri.com/t5/python-questions/optimizing-updatecursor-script/m-p/1366607#M69543</link>
      <description>&lt;P&gt;I'm not going to touch the logic you have that calculates offset. You'll need to review that on your own.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;pt_tbl = "ArcPRO_MasterQuery_EXT_pt"

pt_tbl_fields = ["DISTANCE", "DESCRIPTION_1", "DESCRIPTION_2", "DESCRIPTION_3", "Offset"]
trail_num_sec = ["11-1", "11-2"]
comma_sep_str = ",".join([f"'{i}'" for i in trail_num_sec])
expression = f"NUM_SEC in({comma_sep_str})"

oor = {}
oo  = {}
with arcpy.da.UpdateCursor(pt_tbl, pt_tbl_fields, expression) as u_cursor:
    for distance, desc_1, desc_2, desc_3, offset in u_cursor:
        oo[distance] = oo.get(distance, 0) + 1

        if "RHS" in [desc_1, desc_2, desc_3]:
            oor[distance] = oor.get(distance, 0) + 1

            offset = (oo[distance] - 1) * -1

        elif distance in oor:
            offset = (oo[distance] - (oor[distance]+1))
        else:
            offset (oo[distance] - 1)

        u_cursor.updateRow([distance, desc_1, desc_2, desc_3, offset])

print("Point Table Offsets Calculated")&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Thu, 04 Jan 2024 23:18:29 GMT</pubDate>
      <guid>https://community.esri.com/t5/python-questions/optimizing-updatecursor-script/m-p/1366607#M69543</guid>
      <dc:creator>BlakeTerhune</dc:creator>
      <dc:date>2024-01-04T23:18:29Z</dc:date>
    </item>
    <item>
      <title>Re: Optimizing UpdateCursor Script</title>
      <link>https://community.esri.com/t5/python-questions/optimizing-updatecursor-script/m-p/1367481#M69563</link>
      <description>&lt;P&gt;I feel like this post solves all of the main issues I saw really well, but I want to emphasize a couple points that burned me early on, when I couldn't figure out why my code was taking forever to run:&lt;/P&gt;&lt;P&gt;1. The Data Access Cursors have a ton of work to do and can be more computationally intensive than you might think.&amp;nbsp; Avoid calling them inside loops like this unless you want to go through your whole dataset multiple times.&amp;nbsp; &lt;EM&gt;(&lt;STRONG&gt;Especially&lt;/STRONG&gt; avoid calling Cursor loops inside other Cursor loops.&amp;nbsp; That way madness lies.)&lt;/EM&gt;&amp;nbsp; It's often much better for the Cursor to be your outermost loop, and do whatever other operations you have to do inside that cursor loop.&lt;/P&gt;&lt;P&gt;2.&amp;nbsp;&lt;a href="https://community.esri.com/t5/user/viewprofilepage/user-id/1371"&gt;@JoshuaBixby&lt;/a&gt;&amp;nbsp;'s comment up above condensing your first Cursor is a great example of using the speed of list comprehension to your advantage.&amp;nbsp; To avoid getting technical, even though his script looks like it's just a compression of yours into a single line, it's more efficient than even just that.&amp;nbsp; List comprehension does a bunch of stuff behind the scenes in more efficient form, and you can often save processing time there.&lt;/P&gt;</description>
      <pubDate>Mon, 08 Jan 2024 17:28:38 GMT</pubDate>
      <guid>https://community.esri.com/t5/python-questions/optimizing-updatecursor-script/m-p/1367481#M69563</guid>
      <dc:creator>MErikReedAugusta</dc:creator>
      <dc:date>2024-01-08T17:28:38Z</dc:date>
    </item>
  </channel>
</rss>

