Select to view content in your preferred language

Python script if/for/while

6152
22
Jump to solution
07-09-2015 09:46 AM
CoyPotts1
Deactivated User

*UPDATE*

For samples of the correct code, see posts below.

I'll start off by apologizing for not having any sort of sample of my code, but I am really just unsure on how to begin the code, so all I have is notes of what I need.

I have a feature class that has a number of fields that are duplicated for 5 different customers.  The fields that I need to focus on in this exercise are the Cust1Name, Cust1NodeID, Cust1HomeID, and 10 Cust1CircuitID fields.  I'm using "Cust1", "Cust2", etc only as examples in place of their actual names...just stating that to eliminate your efforts in trying to add the customer number in a potential for/while loop.  Essentially the fields look as they do below:

Cust1Name

Cust1NodeID

Cust1HomeID

Cust1CircuitID1

...

Cust1CirctuitID10

Cust2Name

Cust2NodeID

Cust2HomeID

Cust2CircuitID1

...

Cust2CircuitID10

etc...

My feature class has fields for all 5 customers, but not all 5 will be populated.  I've used the Cust#NodeID field as my reference for whether calculations will run or not because that field determines if they are needed or not.  Populated means run the calculation, while Null means do nothing.

if Cust1NodeID != None:
     return # insert calculation here
else:
     return None

I also need to get a users input to know the amount of circuit ID's needed.  The number varies from 1 to 10 circuit ID's.

numberIDs = arcpy.GetParameterAsText(0)

With this information I need the script to go through each Cust#NodeID field to check and see if it's null or not.  If it's null, keep moving...if it has data, calculate the amount of circuit ID fields needed based on the input.


Again, sorry for having nothing to start with.  I'm just confused on which route to take (for loop, while loop, if/if...), and I can't figure out any of them either way.  I'm just not sure how to add so many arguments together.

*EDIT*

I'll also note that the circuit ID calculation itself is just a concatenation of the given fields, as shown below:

Cust1CircuitID1 = (Cust1Name) - (Cust1NodeID) - (Cust1HomeID) - (01)

Cust1CircuitID2 = (Cust1Name) - (Cust1NodeID) - (Cust1HomeID) - (02)

etc...

0 Kudos
1 Solution

Accepted Solutions
DarrenWiens2
MVP Honored Contributor

Until you've got more, it's hard to help. You almost certainly need to use a SearchCursor (to read) or UpdateCursor (to read/write) to loop through your records. Is that the missing piece?

View solution in original post

22 Replies
DarrenWiens2
MVP Honored Contributor

Until you've got more, it's hard to help. You almost certainly need to use a SearchCursor (to read) or UpdateCursor (to read/write) to loop through your records. Is that the missing piece?

CoyPotts1
Deactivated User

The UpdateCursor method works wonders, but I can't seem to get the string portion of the return calculation to work properly.  It keeps returning a literal string.  I tried single quotes, and I tried ' """ + var + "" ' both with an without the space in between, and I just kept getting a literal string. 

import arcpy

numIDs = arcpy.GetParameterAsText(0) # I equaled this to 1 in my testing to see if it would ignore CircuitID2 and it did
fc = r'my node feature class'
fields = ('Cust1NodeID', 'Cust1HomeID', 'Cust1Name', 'Cust1CircuitID1', 'Cust1CircuitID2', 'Cust1CircuitID3', 'Cust1CircuitID4', Cust1CircuitID5', 'Cust1CircuitID6', 'Cust1CircuitID7', 'Cust1CircuitID8', 'Cust1CircuitID9', 'Cust1CircuitID10')

with arcpy.da.UpdateCursor(fc, fields) as cursor:

     for row in cursor:
          if row[0] != None:
               row[3] = "(" + Cust1Name + ") - (" + Cust1NodeID + ") - (" + Cust1HomeID + ") - (01)"
          elif (row[0] != None and numIDs >= 2):
               row[4] = "(" + Cust1Name + ") - (" + Cust1NodeID + ") - (" + Cust1HomeID + ") - (02)"

This runs through and only updates Cust1CircuitID1, but I just need to get over the whole literal string hand up.  I only wrote it out to calculate the first two CircuitID fields, but as my script note above states, I set the variable to 1 so that it would only calculate the first one.


I've seen the UpdateCursor function in other code samples, and I've seen reference to it, but I haven't tried it yet.  Glad your suggestion led me to do a little research and learn it a little better .  I'll likely be going back and updating some other code that I've created using this method.

0 Kudos
DarrenWiens2
MVP Honored Contributor

The values in the cursor are accessed according to their position in the fields list:

fields = ('Cust1NodeID', 'Cust1HomeID', 'Cust1Name', 'Cust1CircuitID1', 'Cust1CircuitID2', 'Cust1CircuitID3', 'Cust1CircuitID4', Cust1CircuitID5', 'Cust1CircuitID6', 'Cust1CircuitID7', 'Cust1CircuitID8', 'Cust1CircuitID9', 'Cust1CircuitID10')

...corresponds to indexed values:

row[0], row[1], row[2], ..., row[12]

So, to access the value in the Cust1Name position, you would use the value:

row[2]

... rather than Cust1Name.

DanPatterson_Retired
MVP Emeritus

or as Xander has suggested on a few occasions..before the

Cust1NodeID = row[0]

Cust1HomeID = row[1]

...

for row in rows:

  then you can use their names

or you could also unwrap the args

Cust1NodeID, Cust1HomeID = row # or fields

but I haven't got a file to check

CoyPotts1
Deactivated User

Yeah, I noticed how the row corresponded with each position in the variable list, but I didn't realize that I would use the actual "row" nomenclature for the variable in the concatenation.  That did the trick! 


Thanks once again, !  I'm very thankful for people like you and

0 Kudos
CoyPotts1
Deactivated User

Does the code have the ability to step through each row and update them accordingly?  In my example above the first line simply checks to see if the NodeID field is populated, and then if so it updates the CircuitID1 field.  However, the second line checks whether the NodeID field is populated AND if the input variable is > or = to 2, and if so it updates the CircuitID2 field.

In the example above I used an input value of 1 just to see if it would stop there and not calculate the 2nd, and it seemed to work, but I believe it did for unwanted reasons.  When I change the input variable to 2, the second line still doesn't calculate.  If I remove the first line altogether and just run the second line, it populates the CircuitID2 field correctly.

Ideally the code should step through each if statement, check the parameters, and conditionally update the corresponding field below it, right?

if NodeID != None:
     calculate CircuitID1
elif NodeID != None and input variable >= 2:
     calculate CircuitID2
elif NodeID != None and input variable >= 3:
     calculate CircuitID3

etc...

So if I input 4, it'll update CircuitID1, 2, 3, and 4.  However, if I only put 1, it'll update just CircuitID1.  Is that not the way it should work?

0 Kudos
CoyPotts1
Deactivated User

The actual code that I used that doesn't update both the if and elif is below:

import arcpy

numIDs = 2
fc = r'my node feature class'
fields = ('NodeID', 'HomeID', 'CustName', 'CircuitID1', 'CircuitID2')

with arcpy.da.UpdateCursor(fc, fields) as cursor:
     for row in cursor:
          if row[0] != None:
               row[3] = "(" + row[2] + ") - (" + row[0] + ") - (" + row[1] + ") - (01)" # this works fine
          elif row[0] != None and numIDs >= 2):
               row[4] = "(" + row[2] + ") - (" + row[0] + ") - (" + row[1] + ") - (02)" # this one won't run
          cursor.updateRow(row)

If I take the elif statement exactly as it is and put it in the if portion, it works, so I know the syntax is there for it to work, but something isn't allowing it to work in tandem with the other in an if/elif/elif/elif/elif format.  When I run it just as it it typed above, it just runs through and updated the first if, and ignores the second.  Any ideas why?

0 Kudos
DanPatterson_Retired
MVP Emeritus

The if, elif, statement will only get past into the if section

if row[0] != None:

it will never see the elif section unless you provide a condition for the condition where numIDs < 2 ... like

if  (row[0] != None) & (numIDs < 2):

    do stuff

elif  blah

    blah

cursor.updateRow

However this logic is also flawed potentially.  Do you want the cursor to be updated if row[0] is = None???

perhaps your logic should be

if  (row[0] != None):
    if numIDs < 2:
        row[3] = "(" + row[2] + ") - (" + row[0] + ") - (" + row[1] + ") - (01)" # this works fine 
    else
        row[4] = "(" + row[2] + ") - (" + row[0] + ") - (" + row[1] + ") - (02)" # this one won't run  
    cursor.updateRow(row)
0 Kudos
CoyPotts1
Deactivated User

If row[0] has a null value, then I want the script to return nothing.  Basically if there is no node name, then we don't need a circuit ID for that node.

I ran the following samples and got different errors with each:

for row in cursor:
     if (row[0] != None):
          if (numIDs == 1):
               row[3] = "(" + row[2] + ") - (" + row[0] + ") - (" + row[1] + ") - (01)"
          elif (numIDs == 2)
               row[3] = "(" + row[2] + ") - (" + row[0] + ") - (" + row[1] + ") - (01)"
               row[4] = "(" + row[2] + ") - (" + row[0] + ") - (" + row[1] + ") - (02)"
          cursor.updateRow(row)


This returns the error message:

"Parsing error SyntaxError: EOL while scanning string literal (line 16)"

for row in cursor:
     if (row[0] != None) & (numIDs < 2):
          row[3] = "(" + row[2] + ") - (" + row[0] + ") - (" + row[1] + ") - (01)"
     elif (row[0] != None) & (numIDs < 3):
          row[3] = "(" + row[2] + ") - (" + row[0] + ") - (" + row[1] + ") - (01)"
          row[4] = "(" + row[2] + ") - (" + row[0] + ") - (" + row[1] + ") - (02)"
     cursor.updateRow(row)

This returns the error message:

"Runtime error

Traceback (most recent call last):

  File "<string>", line 16, in <module>

TypeError: coercing to Unicode: need string or buffer, NoneType found"

0 Kudos