Buscar si el campo existe en la clase de entidad

8

Tengo unas pocas docenas de clases de entidad, una de las cuales contiene el campo que estoy buscando. Se almacenan en varias geodatabases de archivos diferentes.

¿Hay una forma rápida de buscar en cada clase de entidad para encontrar la que tiene mi campo? ¿O tengo que verificar la tabla de atributos de cada uno en el Catálogo? Algunos de los archivos tienen los mismos nombres pero se almacenan en ubicaciones separadas.

Me gustaría poder hacer esto dentro de una Calculate Valueherramienta en ModelBuilder, para que cada vez que lo necesitara, pudiera ejecutar el modelo en un solo archivo gdb y buscaría en todas las clases de entidad dentro de ese gdb y buscar el campo .

Hasta ahora, tengo un iterador de clase de entidad que itera sobre todas las clases de entidad en el archivo gdb de forma recursiva. Dentro del Calculate Valuetengo el siguiente código:

findField(r"%Feature%", "%Search Field%")

def findField(fc, fi):
  lst = arcpy.ListFields(fc)
  for f in lst:
    if f.name == fi:
      return fc
    else:
      return "not found"

Los valores devueltos se recopilan Output Valuescomo cadenas. La salida para todas las clases de entidad no se ha encontrado, aunque el campo exista en al menos 4 de ellas. ingrese la descripción de la imagen aquí

Cindy Jayakumar
fuente
¿De qué estás tratando de calcular el valor? ¿Estás intentando insertar registros en una tabla? No tiene mucho sentido para qué está tratando de usar la herramienta Calcular valor para ...
RyanKDalton
Puse el código de Python dentro Calculate Valuepara buscar el campo y devolver la ruta de la clase de entidad como una cadena si encuentra el campo; vea mi respuesta a continuación.
Cindy Jayakumar

Respuestas:

4

Preferiría una comprensión de la lista en lugar de operaciones de cadena (como la respuesta aceptada). En mi opinión, esto es más legible y pitónico. Además, el enfoque de comprensión de la lista podría ampliarse agregando funcionalidades adicionales ( str.lower()como hizo @RyanDalton) de manera muy fácil.

def findField(fc, fi):
  fieldnames = [field.name for field in arcpy.ListFields(fc)]
  if fi in fieldnames:
    return "found in " +fc
  else:
    return "not found in " +fc

Si prefiere la declaración if-else de un revestimiento:

def findField(fc, fi):
  fieldnames = [field.name for field in arcpy.ListFields(fc)]
  return "found in " + fc if fi in fieldnames else "not found in " + fc

O incluso más corto, pero menos legible:

    def findField(fc, fi):
      return "found in " + fc if fi in [field.name for field in arcpy.ListFields(fc)] else "not found in " + fc
Saleika
fuente
Sí, esta sería la respuesta preferible ahora. Hice esta pregunta hace mucho tiempo, me duele recordar los 9 meses que desperdicié en ModelBuilder antes de cambiarme a Python por completo en lugar de piratear partes y piezas.
Cindy Jayakumar
19

Echa un vistazo a esta función de Bjorn Kuiper para probar si existe un campo :

def FieldExist(featureclass, fieldname):
    fieldList = arcpy.ListFields(featureclass, fieldname)

    fieldCount = len(fieldList)

    if (fieldCount == 1):
        return True
    else:
        return False

con el siguiente ejemplo de uso:

    if (not FieldExist(myFeatureClass, "myField")):
      arcpy.AddError("Field 'myField' does not exist in " + myFeatureClass)
      sys.exit()
Dana
fuente
Terminé usando algo similar hace un tiempo, pero no me dio el resultado que estaba buscando.
Cindy Jayakumar
12

puedes usar arcpy:

import arcpy

myField = "test"

env.workspace = "D:/test/data.gdb"
fcs = arcpy.ListFeatureClasses()

for f in fcs:
    fieldList = arcpy.ListFields(f)
    for field in fieldList:   
         if field.name == myField:
             print f

Además de esto, puede usar os.walk para archivos en su disco como:

path = r"C:"
for root, dirs, files in os.walk(path):
    for fileName in files:
            .........

Espero que te ayude....

Aragón
fuente
Lo probé, y aunque el código tiene sentido, no hace nada. Lo probé usando un campo que está en cuatro de mis clases de entidad: el script se ejecutó pero no generó nada.
Cindy Jayakumar
oh, lo siento, me olvido de hacer un bucle de campos en el conjunto de campos, ahora actualizo mi respuesta y la he probado.
Aragón
He intentado con el código actualizado, se ejecuta pero no tiene salida aunque el campo está en varias clases de entidad dentro de la geodatabase.
Cindy Jayakumar
3

Arabella, ¿son tus clases de características en conjuntos de datos de características? Si es así, la solución de @ Aragon no funcionará porque necesita recorrer los conjuntos de datos de características y luego verificar las clases de características.

Utilizando el código de @ Aragon y el código de @ gotchula de Listar todas las clases de entidades en GDB, incluso dentro de los conjuntos de datos de entidades, produje el siguiente código que leerá todos los conjuntos de datos y clases de entidades en una geodatabase.

NOTA : Por defecto, ListFields parece ser sensible a mayúsculas y minúsculas. He agregado código para convertir tanto el nombre de campo definido por el usuario como el nombre de ListField a minúsculas para búsquedas que no distinguen entre mayúsculas y minúsculas. Probablemente también desee deshabilitar la mayoría de las declaraciones de impresión, pero las dejé allí para que pueda seguir el código mientras se ejecuta. También creé la subfunción FindField dentro de para poder llamarla varias veces en el script sin tener que volver a codificarla.

import arcpy

def FindField(fc,myField):
    fieldList = arcpy.ListFields(fc)
    for field in fieldList:
        if str.lower(str(field.name)) == str.lower(myField):
            print "    " + fc + " contains fieldname: " + myField

myField = "test"
arcpy.env.workspace = "D:/test/data.gdb"

#Search root level featureclasses
for fc in arcpy.ListFeatureClasses():
    print "Searching root level Featureclasses..."
    print "  Searching " + fc
    FindField(fc,myField)

#Search Feature Datasets
for fds in arcpy.ListDatasets('','feature'):
    print "Searching FeatureDataset: " + fds

    for fc in arcpy.ListFeatureClasses('','',fds):
        print "  Searching Featureclass... " + fc
        FindField(fc,myField)
RyanKDalton
fuente
Estaría ejecutando esto en un modelo, así que lo adapté un poco y lo probé. Sin Calculate Valueembargo, no estoy seguro de qué quiero que regrese, ¿podría return "true" if FindField(fc,myField) =="true" else "false"?
Cindy Jayakumar
Ah, acabo de darme cuenta de que mi comentario anterior no me diría nada. También ejecutar esa prueba booleana dentro del modelo no devuelve nada.
Cindy Jayakumar
Calcule el valor? Prueba booleana? Creo que deberías aclarar tu pregunta sobre qué es exactamente lo que buscas.
RyanKDalton
He editado la pregunta.
Cindy Jayakumar
2

Algunos han bailado en torno a la forma en que haría esto, pero solo quiero agregar una forma sencilla de una línea para hacer esto:

if 'fieldname' in [f.name for f in arcpy.ListFields(fc)]:
    ## do something.

Lo que quizás sea más útil (si está iterando a través de muchas clases de entidad) usaría lo contrario de lo anterior como filtro:

for fc in arcpy.ListFeatureClasses():
    if not 'fieldname' in [f.name for f in arcpy.ListFields(fc)]:
        continue
    ## now do something with the feature class.
Sr. Adam
fuente
1

Encontré la respuesta con ayuda del código en la respuesta a esta pregunta . Tomé todos los nombres de campo, los convertí en una cadena y luego busqué en la cadena mi campo. El código en el Calculate Valueahora se ve de la siguiente manera:

def findField(fc, fi):
  fieldList = arcpy.ListFields(fc)
  nameList = []
  for f in fieldList:
    nameList.append(f.name)
  str_lst = "!" + "!, !".join(nameList) + "!"
  return "found in" +fc if str_lst.find(fi) > 0 else "not found in " +fc

El Output Valuesahora contiene la lista completa de clases de entidad que tiene el campo que busqué y not foundel resto.

Recopilar salida de valores

Cindy Jayakumar
fuente