[GIS] Using Python in the field calculator – if/else over multiple fields

arcgis-desktopfield-calculatorpython

I'm trying to work out how to populate a field depending on the lowest score across 6 other fields. I've read several other questions relating to if/else statements but I'm only just starting to learn Python so I'm struggling to put together any code that works.

I'm trying to populate a 'Main Failing' field, where for each object ID in the feature class the worst scored field out of 6 other fields will be noted.

The other fields are: 'Interconnectivity', 'PropCover', 'PatchSize', 'ShapeIndex', 'Naturalness' and 'EdgeNat' and they are all short integer, with high numbers being better than low numbers.

So for example if 'Interconnectivity' had the lowest score across the 5 fields for one objectID, I would like to work out how to populate the 'Main Failing' column for that objectID with text saying 'Interconnectivity'.

Edited:
Here's an example of the code I've tried so far with Branco's help. It's running without errors but is either leaving the MainFailing field blank (if 'return resultList[0]') or is populating it with 0's (if return resultList[1]).

Codeblock:

myFunction( !InterconnectivityScore!, !PropCoverScore!, !PatchSizeScore!, !ShapeIndexScore!, !NatScore!, !EdgeNatScore!)

Pre-logic script code:

def myFunction ( interconnectivityScoreValue, propCoverScoreValue, patchSizeScoreValue, shapeIndexScoreValue, natScoreValue, edgeNatScoreValue):
resultList = ["",0]
if interconnectivityScoreValue <= resultList[1]:
    resultList[0] = "Interconnectivity"
    resultList[1] = InterconnectivityScore
if propCoverScoreValue <= resultList[1]:
    resultList[0] = "ProportionalCover"
    resultList[1] = PropCoverScore
if patchSizeScoreValue <= resultList[1]:
    resultList[0] = "PatchSize"
    resultList[1] = PatchSizeScore
if shapeIndexScoreValue <= resultList[1]:
    resultList[0] = "ShapeIndex"
    resultList[1] = ShapeIndexScore
if natScoreValue <= resultList[1]:
    resultList[0] = "Naturalness"
    resultList[1] = NatScore
if edgeNatScoreValue <= resultList[1]:
    resultList[0] = "EdgeNaturalness"
    resultList[1] = EdgeNatScore
return resultList[1]

Best Answer

Try this (edited per @alpha-beta-soup comment):

def myFunction (inter, prop, patch, shp, nat, edge):
    myList = [inter, prop, patch, shp, nat, edge]
    myList.sort()
    myDict = {'Interconnectivity' : inter,
              'PropCover' : prop,
              'PatchSize' : patch,
              'ShapeIndex': shp,
              'Naturalness' : nat,
              'EdgeNat' : edge}

    myVal = 101   # using 101 as a max + 1 possible value; adjust if needed
    myReturn = ''
    for k, v in myDict.iteritems():
        if v < myVal:
            myVal = v
            myReturn = k

    return myReturn

Note that if you have two matching low values, there's nothing to select one over the other. That would require additional checking based on whatever your criteria is. Since a dictionary is unordered, you can't control it that way.

Here's another way without dictionaries, with an optional clause for ties. You may want different logic in case of ties.

def myFunction2 (inter, prop, patch, shp, nat, edge):
    # use tuples to ensure value order
    myScoreTuple = (prop, patch, shp, nat, edge)
    myTextTuple = ('PropCover',
                   'PatchSize',
                   'ShapeIndex',
                   'Naturalness',
                   'EdgeNat')

    # initialize values
    myLowValue = inter
    myReturn = 'Interconnectivity'

    # now check for any lower value
    for i in range(len(myScoreTuple)):
        if myScoreTuple[i] < myLowValue:
            myLowValue = myScoreTuple[i]
            myReturn = myTextTuple[i]

        # optional - add multiple text values in case of tie. Remove if unneeded
        elif myScoreTuple[i] == myLowValue:
            myReturn = ', '.join((myReturn, myTextTuple[i]))

    return myReturn