Select to view content in your preferred language

dict(zip()) in for loop with Calc Field codeblock

1446
10
Jump to solution
10-08-2023 02:54 PM
coolflippers
Regular Contributor

Good evening, some trouble with the below example code. This is my first time putting a loop in a function for Calculate Field. I've tried a number of ways (putting brackets after row in the condition of the for loop, putting a 0 inside the brackets, changing the equals sign, trying the brackets with Key, etc).

 

KeyList = ['a','b','c']
ValueList = ['chair','lamp','rug']
Dict = dict(zip(KeyList,ValueList))​
codeblock = """
def output(Key,Value):
    for row in KeyList:
        if row == Key:
            return Dict[KeyList]
        else:
            return Value"""​

 

TableExample:

ID

NAME(NewField)

a

 (chair)
zdesk(desk)
c (rug)

 

arcpy.management.CalculateField(
    in_table = "TableExample",
    field = "NewField",
    expression = "output(!ID!,!NAME!)",
    expression_type = "PYTHON3",
    code_block = codeblock
    )​

 

0 Kudos
1 Solution

Accepted Solutions
coolflippers
Regular Contributor
codeblock = """
def output(Key,Value):
    for row in KeyList:
        if row == Key:
            return Dict[KeyList]
     for row in KeyList:
        if row != Key:
            return Value"""

This is my fix. Not that neat though. I feel like somebody probably has a better idea...

View solution in original post

0 Kudos
10 Replies
coolflippers
Regular Contributor

I am noticing something about this. I can get it to run, but only for the first row. In my scenario, I have a few hundred rows between ID cell 'a' and ID cell 'c'. I run my code, and NewField populates correctly based on the ID in row 1 and the NAME and row 2. So, my NewField, as applied to this example, is correct for its first two cells. However, on its third cell, which, in this example, should be 'rug', in my scenario in Arc it's blank. It's as if the function was satisfied on the first row, and then went to the else statement for all the remaining rows. hm. maybe i should do two for loops. let me try that

0 Kudos
coolflippers
Regular Contributor

Symptom verified. I took out the else statement, and all the values in ValueList were calculated into the field. Now, I just need to figure out how to populate the remaining fields based off NAME without messing up my progress...

0 Kudos
coolflippers
Regular Contributor

This is what my table looks like before calc field:

coolflippers_0-1696803511818.png

 

0 Kudos
coolflippers
Regular Contributor

If I include the else statement, only field in the list populates correctly: 

coolflippers_1-1696803601333.png

 

0 Kudos
coolflippers
Regular Contributor

But, when I delete the 'else' statement, the new field populates correctly off the list (of course omitting all the remaining fields)

coolflippers_2-1696803703404.png

 

0 Kudos
DanPatterson
MVP Esteemed Contributor

Is this what you are trying to do?

KeyList = ['a','b','c']
ValueList = ['chair','lamp','rug']
Dict = dict(zip(KeyList,ValueList))

def output(id_val, Dict):
    if id_val in Dict.keys():
        return (f"({Dict[id_val]})")
    else:
        return None
        

for i in ['a', 'z', 'c', 'd', 'a']:
    print(output(i, Dict))
    
(chair)
None
(rug)
None
(chair)

... sort of retired...
coolflippers
Regular Contributor

I'm not sure. I feel like what you posted is probably a better way to do it. I've never used the .keys function.

0 Kudos
coolflippers
Regular Contributor
codeblock = """
def output(Key,Value):
    for row in KeyList:
        if row == Key:
            return Dict[KeyList]
     for row in KeyList:
        if row != Key:
            return Value"""

This is my fix. Not that neat though. I feel like somebody probably has a better idea...

0 Kudos
AlfredBaldenweck
MVP Regular Contributor

So, first thing: the dict(zip()) with two lists is cool, but dictionaries can also just be manually made if that's easier.

 

keyDict = {a:red, b:blue, ...}
#Code

 

 

The other thing that you can try is a dictionary Get() method. This will return the value from the dictionary if the key is there OR else return a default value specified in the second parameter of the method. If you leave the second parameter empty, it will default to None, but you can also manually make it that way.

 

keyDict = {"a":"red", "b":"blue", "c":"yellow"}
res = keyDict.get("a", "white")
print(res)
# red

res = keyDict.get("d", "white)
print(res)
# white

# The None does not have any quotes on purpose.
# It is truly no value, not the word "None".
res = keyDict.get("d", None)
print(res)
# None
res = keyDict.get("e")
print(res)
# None

 

 

So, give this a shot? 

 

# I think I messed up with the actual function part here
# but the code inside is good.

def output():
    KeyList = ['a','b','c']
    ValueList = ['chair','lamp','rug']
    # (Don't name your variables after functions, including "dict")
    keyDict = dict(zip(KeyList,ValueList))

    for key in KeyList:
        return keyDict.get(key, None)

 

 

0 Kudos