2

I have the following script that is used with a script tool to truncate each word in an input string and output the result to another field. There is an input parameter for the length of the truncation.

import arcpy
arcpy.env.overwriteOutput = True

# Prelogic used to pass through for calculating truncated name values
codeblock = """
def nmshort(stname,stnum):
  s = stname.split()
  s2 = s[:] = [elem[:stnum] for elem in s]
  s3 = ' '.join(s2)
  if s3 == stname:
    return None
  else:
    return s3
""" # Finished code block

try:
    # Set input parameters
    inFC = arcpy.GetParameterAsText(0)
    inName = arcpy.GetParameterAsText(1)
    inNameShort = arcpy.GetParameterAsText(2)
    inNumber = arcpy.GetParameterAsText(3)

    # set expression for field calculation to variables
    expression = "nmshort(!{0}!, {1})".format(inName,int(inNumber))

    # perform field calculation
    arcpy.AddMessage("Calculating truncated strings for values in input name field")
    arcpy.CalculateField_management(inFC, inNameShort, expression, "PYTHON_9.3", codeblock)
    arcpy.AddMessage("Calculation complete")

except:
    arcpy.AddError("Could not complete the calculation")

    arcpy.AddMessage(arcpy.GetMessages())

How would I accomplish this same calculation using a cursor instead of CalculateField? I'm using ArcGIS 10.0 so I won't be able to use the data access cursors. I've used cursors successfully involving simpler expressions (one line'ers) but I can't figure out how to do it for multiple process steps.

I applied Paul's answer as follows:

import arcpy
arcpy.env.overwriteOutput = True

# Prelogic used to pass through for calculating truncated name values

def nmshort(stname,stnum):
    s = stname.split()
    s2 = s[:] = [elem[:stnum] for elem in s]
    s3 = ' '.join(s2)
    if s3 == stname:
        return None
    else:
        return s3

try:
    # Set input parameters
    inFC = arcpy.GetParameterAsText(0)
    inName = arcpy.GetParameterAsText(1)
    inNameShort = arcpy.GetParameterAsText(2)
    inNumber = arcpy.GetParameterAsText(3)

    # set expression for field calculation to variables
    arcpy.AddMessage("Calculating truncated strings for values in input name field")
    cursor = arcpy.UpdateCursor(inFC)
    for row in cursor:
        row.setValue(inNameShort, nmshort(inName,int(inNumber)))
        cursor.updateRow(row)

    del row, cursor

    arcpy.AddMessage("Calculation complete")

except:
    arcpy.AddError("Could not complete the calculation")

    arcpy.AddMessage(arcpy.GetMessages())

The values all come back as "PLAC" for each row. "PLACENAME" is the field name that was used as the input.

  • Why would you need to switch to cursors if your workflow does the job? 10.0 cursors are slow and there is a good chance running the Calculate Field would be actually much faster than creating cursors. – Alex Tereshenkov Sep 21 '15 at 17:45
  • 1
    @AlexTereshenkov debugging multi-line codeblocks is not a straightforward task. I'd go with cursors for that reason alone. – Paul Sep 21 '15 at 17:59
  • @AlexTereshenkov - I think you make a valid point, if my question would have been centered on "which of these methods is faster". In this case, I'm trying to expand my understanding of cursors and how to use them to accomplish manipulations that involved more complex logic than a single line expression. Paul's explanation is also a big motivation behind my question. – Hoss Sep 21 '15 at 21:04
3

Since you already have a function in your code-block, you can just re-use it in your cursors.

Here's the untested code to get you started:

def nmshort(stname,stnum):
    s = stname.split()
    s2 = s[:] = [elem[:stnum] for elem in s]
    s3 = ' '.join(s2)
    if s3 == stname:
      return None
    else:
      return s3


cursor = arcpy.UpdateCursor(inFC)
for row in cursor:
    row.setValue(inNameShort, nmshort(row.getValue(inName), int(inNumber)))
    cursor.updateRow(row)

del row, cursor
  • I agree with this answer - Will the difference in indentation matter to the python interpreter? 2 spaces in the function definition and 4 spaces in the for loop? – Jim Sep 21 '15 at 18:13
  • @Jim, it shouldn't matter. I just copied OP's code into my IDE and forgot to check. Thanks for pointing it out! – Paul Sep 21 '15 at 18:17
  • @Paul - I think I'm closer. The result got written as "PLAC" for all rows. My input field name was "PLACENAME". So I'm off somewhere. I don't think I can post the code in whole context in a comment (still learning how to use this site correctly) so I'll add it to my question. – Hoss Sep 21 '15 at 21:11
  • @Hoss, see my updated code. I'm not all that familiar with the old cursors. – Paul Sep 21 '15 at 21:46
  • @Paul, from what I've seen the data access cursors are much better. I think we're close based on other examples I've seen. Your amended code gave me an error on the row.setValue line but no info as to why. That doesn't give either of us much to work from, haha. You may have given me enough to apply from other examples related to this though (with a little trial and error). I started with something similar to the above (using the function as a parameter to the cursor) but I wasn't sure if I could do that. – Hoss Sep 21 '15 at 22:18
1

After some further tinkering with Paul's example, I came to the following solution.

def nmshort(stname,stnum):
    s = stname.split()
    s2 = s[:] = [elem[:stnum] for elem in s]
    s3 = ' '.join(s2)
    if s3 == stname:
        return None
    else:
        return s3

try:
    cursor = arcpy.UpdateCursor(inFC)
    for row in cursor:
        name=row.getValue(inName)
        length=int(inNumber)
        if name:
            outVal = nmshort(name,length)
            row.setValue(inNameShort, outVal)
            cursor.updateRow(row)
    del row, cursor

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.