7 votos

Cómo iterar los campos y eliminar los valores nulos y los espacios

¿Es posible iterar los campos de una tabla para eliminar los valores nulos y los espacios (donde no hay valor)? En otras palabras, me gustaría sustituir Null y " " por "" (sin espacio).

Cobrando los scripts de Arcpy, tengo esto:

import arcpy

fc = "{path to geodatabase and feature class}"
fieldList = arcpy.ListFields(fc)
for field in fieldList:
    with arcpy.da.UpdateCursor(fc, [fieldList]) as cursor:
        for row in cursor:
            if row[0] == None:
                row[0] = ''
            elif row[0] == ' ':
                row[0] = ''
                cursor.updateRow(row)

print "Processing complete"

Soy consciente de que se puede utilizar "eliminar" en la calculadora de campos, pero hay que ir campo por campo. Me gustaría hacer esto para toda la tabla.

4voto

Flinkman Puntos 4821

Creo que lo has entendido al revés. No for field in fieldList entonces for row in cursor , más bien for row in cursor y for field in fieldList excepto que necesitarás indexar correctamente... sólo estás intentando ajustar el primer campo de la fieldList con row[0].

import arcpy

fc = "{path to geodatabase and feature class}"
fieldList = arcpy.ListFields(fc)
# remove some key fields from the list
desc = arcpy.Describe(fc)

fieldList.remove(desc.shapeFieldName)
fieldList.remove(desc.OIDFieldName)

with arcpy.da.UpdateCursor(fc, [fieldList]) as cursor:
    fRange = range(len(fieldList)) # create an index 0 to the number of elements in fieldList - 1

    for row in cursor:
        SomethingUpdated = False # a flag for changes

        # step through each field in the row by its index
        for index in fRange:
            if row[index] == None:
                row[index] = ''         #set the field to empty string
                SomethingUpdated = True #flag to store row
            else:
                val = str(row[index]).replace(" ","") # remove spaces
                if len(val) == 0:
                    # value is nothing but spaces or empty
                    row[index] = ''         #set the field to empty string
                    SomethingUpdated = True #flag to store row

        if SomethingUpdated:
            cursor.updateRow(row)

print "Processing complete"

Tenga en cuenta que no se realiza ninguna comprobación de los tipos de campo; ¡intentar poner '' en un campo numérico hará que este script se cuelgue con fuerza!

3voto

Tedy Puntos 46

Voy a ofrecer mi variación:

import arcpy

fc = "{path to geodatabase and feature class}"

fieldList = [f.name for f in arcpy.ListFields(fc) if f.type == "String"]

if fieldList:

    with arcpy.da.UpdateCursor(fc, [fieldList]) as cursor:
        for row in cursor:
            for i in range (len(fieldList)):
                if not row[i]:
                    row[i] == ""
                elif row[i] == " ":
                    row[i] == ""
            cursor.updateRow(row)

print "Processing complete"

0 votos

Me gusta cómo has confeccionado tu lista de campos con sólo cadenas de caracteres. Los usuarios nuevos en python pueden encontrar la sintaxis de una sola línea un poco confusa, te importaría ampliar la construcción de la lista de campos por favor.

0 votos

Me gusta esta respuesta, aunque para estar más seguro modificaría ligeramente el elif: elif row[i].rstrip() == "": ... De esta manera también recogerás cualquier instancia de 2 o más espacios.

1 votos

@Michael Esa sintaxis de formación de listas también me costó un tiempo meterla en la cabeza. el formato básico es [{código}var{código} para var en [lista] si var{prueba lógica}]. La sintaxis es un método de trabajo con listas para crear otras listas. Así que para mi código, la nueva lista se rellena con el nombre de cada objeto de campo del código listfields si el tipo de ese campo es cadena. Probablemente ahora tenga menos sentido.

2voto

UnkwnTech Puntos 21942

No estoy seguro de entender lo que preguntas, porque tu pregunta no describe lo que no funciona en tu código, pero creo:

    for row in cursor:
        if row[0] == None:
            row[0] = ''
        elif row[0] == ' ':
            row[0] = ''
            cursor.updateRow(row)

tiene que ser:

    for row in cursor:
        if row[0] == None:
            row[0] = ''
        elif row[0] == ' ':
            row[0] = ''
        cursor.updateRow(row)

También tendrá que filtrar los campos de texto de sus otros campos porque son los únicos en los que puede escribir cadenas.

1voto

ESV Puntos 4591

No creo que sea posible calcular para toda una tabla de una sola vez, todavía tendrá que calcular campo por campo.

En cuanto a la realización de la edición, la mejor manera de actualizar los datos sería con arcpy.CalculateField_management - que es efectivamente la calculadora de campos en su script - en lugar de un Cursor de Actualización (que tiene que operar fila por fila). Puede utilizar una expresión de Python en arcpy.CalculateField_management (o la propia calculadora de campos) para comprobar una cadena y devolver la cadena actualizada, por ejemplo:

(!field_name! or "").strip() # will also strip the trailing spaces

Que puedes lanzar a arcpy.CalculateField_management en un script;

import arcpy

fc = "{path to geodatabase and feature class}"
fieldList = arcpy.ListFields(fc, field_type="String") # don't want to try this on an integer

for field in fieldList:
    expression = """(!{}! or "").strip()""".format(field.name)
    arcpy.CalculateField_management(fc, field.name, expression, "PYTHON_9.3")

0 votos

Mi tabla tiene 52 campos, incluyendo 1 ID de objeto, 1 geometría y 3 campos de tipo doble. Son 47 campos que preferiría no recalcular individualmente para eliminar los valores nulos y los espacios simples. Los 5 campos son bastante obvios y no necesitaría comprobar el tipo antes de ejecutar el cálculo. Simplemente los omitiría. Es que ejecutar el cálculo en 47 campos, uno por uno es súper tedioso.

0 votos

@Lance Lo siento, debería haberlo dejado más claro - puedes llamar a la calculadora de campos como parte de un script de Python con arcpy.CalculateField_management que procesa una columna entera de una vez, en lugar de tener que preocuparse de fila por fila. Respuesta actualizada para reflejar esto.

0 votos

Gracias por la aclaración. He añadido una sentencia print al final para saber cuando se completaba el script. ¡Tardó un poco más de 5 min. en ejecutarse, pero mucho menos tedioso que hacerlo yo! ¡Gracias por tu ayuda!

1voto

Dwayne Reid Puntos 11286
fc = inFeature # feeature class containing the null values
Row = # field containing the null values
selection = arcpy.SelectLayerByAttribute_management(fc, "New_Selection", "Row is NULL") # selects the rows with null values
arcpy.DeleteRows_management(fc) # deletes selected rows

1 votos

Por favor, añade una pequeña explicación a tu código.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X