Select to view content in your preferred language

List Fields with ArcPy

6264
8
Jump to solution
06-10-2015 03:25 PM
KONPETROV
Frequent Contributor

I have a code in the following form. The problem i have is that some shapefiles don't have the specific fields DISTANCE, DURATION, so i tried to write a code with ListFields so as not to exit the commands but to go to the next shapefile. Unfortunately when the script finds a shp with fields which don't have DISTANCE DURATION, it terminates the procedure. Any help would be welcome. This code is in a try except

This is the code:

import arcpy
import os
from arcpy import env
Routesworkspace = arcpy.GetParameterAsText(2)
env.workspace = Routesworkspace
cases = ['RCc10_3_S', 'RCc20_3_S', 'RCc30_3_S', 'RCc40_3_S', 'RCc50_3_S']
SUMDISTANCE = 0
C = 0
for fc in arcpy.ListFeatureClasses():
    for case in cases:
        if fc.startswith(case):
            fields = ['DISTANCE', 'DURATION']
            fieldList = arcpy.ListFields(fc)
            if fields in fieldList:
                with arcpy.da.SearchCursor(fc, fields, "FID = 0") as cursor:
                    a = fc
                    for row in cursor:
                        DISTANCE = row[0]
                        DURATION = row[1]
                        SUMDISTANCE = SUMDISTANCE + DISTANCE
                        C = C + 1
if C > 0:
    AVGDISTANCE = SUMDISTANCE / C
    outFile.write('' + str(int(round(AVGDISTANCE))) + '\n')
else:
    outFile.write('' + str(0) + '\n')
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
FilipKrál
Frequent Contributor

Hi,

Darren is right, I overlooked that. All put together this should work:

import arcpy  
import os  
from arcpy import env  
Routesworkspace = arcpy.GetParameterAsText(2)  
env.workspace = Routesworkspace  
cases = ['RCc10_3_S', 'RCc20_3_S', 'RCc30_3_S', 'RCc40_3_S', 'RCc50_3_S']  
SUMDISTANCE = 0  
C = 0  
for fc in arcpy.ListFeatureClasses():  
    for case in cases:  
        if fc.startswith(case):  
            fields = ['DISTANCE', 'DURATION']  
            fieldList = [f.name for f in arcpy.ListFields(fc)]
            if fields[0] in fieldList and fields[1] in fieldList:  
                with arcpy.da.SearchCursor(fc, fields, "FID = 0") as cursor:  
                    a = fc  
                    for row in cursor:  
                        DISTANCE = row[0]  
                        DURATION = row[1]  
                        SUMDISTANCE = SUMDISTANCE + DISTANCE  
                        C = C + 1  
if C > 0:  
    AVGDISTANCE = SUMDISTANCE / C  
    outFile.write('' + str(int(round(AVGDISTANCE))) + '\n')  
else:  
    outFile.write('' + str(0) + '\n') 

That should do what your original code did except that it will ignore feature classes that do not have both columns DISTANCE and DURATION.

If you wanted to make this more generic, you should consider checking field names in case agnostic way (e.g. convert all field names to lowercase for comparison) and perhaps using set operations if you wanted to check for presence of more than 2 columns.

F.

View solution in original post

8 Replies
BlakeTerhune
MVP Regular Contributor

When you say it terminates, do you get an error message? If so, what exactly does the error message say?

0 Kudos
KONPETROV
Frequent Contributor

No i don't get any errror. The process just stops there because the third fc doesn't have these fields. That's why i put ListFields IF

0 Kudos
FilipKrál
Frequent Contributor

Hi Kon,

The word "terminates" sounds mysterious indeed so any more details about what you can see would help.

Anyway, I think you can fix your code if you simply replace your line 13 with this:

fieldList = [f.name for f in arcpy.ListFields(fc)]

If you are not familiar with list concatenation (the suggestion above), you can write it using a map function too:

fieldList = map(lambda a: a.name, arcpy.ListFields(fc))

The bottom line is that the arcpy.ListFields function returns a list of Field objects, not list of names of fields in the feature class. To get list of names, you need to loop through the list of field objects and retrieve the name propery.

Hope this helps.

Filip.

KONPETROV
Frequent Contributor

Kral thank you for your reply, but if i replace only line 13 nothing changes, just tried.

0 Kudos
DarrenWiens2
MVP Honored Contributor

On top of what Filip says, the logical comparison checking for both fields is incorrect. The way you have it, it is looking for a single item containing both field names to be in the list of fields. It should be:

>>> fields = ['heading','distance']
... fieldList = [f.name for f in arcpy.ListFields("points")]
... if fields[0] in fieldList and fields[1] in fieldList:
...    print "MATCH" # and do other things here
... else:
...    print "NO MATCH" # and do other things here
KONPETROV
Frequent Contributor

Darren i want to calculate shp that have both these fields. If i put an if statement, if a shp doesn't have these specific fields how will the procession continue to the next?

If i understood well you mean something like that right?

for fc in arcpy.ListFeatureClasses():
    for case in cases:
        if fc.startswith(case):
            fields = ['DISTANCE', 'DURATION']
            fieldList = [f.name for f in arcpy.Listfields(fc)]
            if fields[0] in fieldList and fields[1] in fieldList:
                with arcpy.da.SearchCursor(fc, fields, "FID = 0") as cursor:
                    a = fc
                    for row in cursor:
                        DISTANCE = row[0]
                        DURATION = row[1]

It produces the same result

I ALSO get an error AttributeError: 'module' object has no attribute 'Listfields'

FilipKrál
Frequent Contributor

Hi,

Darren is right, I overlooked that. All put together this should work:

import arcpy  
import os  
from arcpy import env  
Routesworkspace = arcpy.GetParameterAsText(2)  
env.workspace = Routesworkspace  
cases = ['RCc10_3_S', 'RCc20_3_S', 'RCc30_3_S', 'RCc40_3_S', 'RCc50_3_S']  
SUMDISTANCE = 0  
C = 0  
for fc in arcpy.ListFeatureClasses():  
    for case in cases:  
        if fc.startswith(case):  
            fields = ['DISTANCE', 'DURATION']  
            fieldList = [f.name for f in arcpy.ListFields(fc)]
            if fields[0] in fieldList and fields[1] in fieldList:  
                with arcpy.da.SearchCursor(fc, fields, "FID = 0") as cursor:  
                    a = fc  
                    for row in cursor:  
                        DISTANCE = row[0]  
                        DURATION = row[1]  
                        SUMDISTANCE = SUMDISTANCE + DISTANCE  
                        C = C + 1  
if C > 0:  
    AVGDISTANCE = SUMDISTANCE / C  
    outFile.write('' + str(int(round(AVGDISTANCE))) + '\n')  
else:  
    outFile.write('' + str(0) + '\n') 

That should do what your original code did except that it will ignore feature classes that do not have both columns DISTANCE and DURATION.

If you wanted to make this more generic, you should consider checking field names in case agnostic way (e.g. convert all field names to lowercase for comparison) and perhaps using set operations if you wanted to check for presence of more than 2 columns.

F.

KONPETROV
Frequent Contributor

WORKS EXCELLENT

0 Kudos