Hello,
I'd like to do some complicated field calculation.
I want to calculate the Field 6-value (see table below, representing a FeatureClass table) as follows:
If Field 1 = 617: Field 3-value
Else: Field 2-value
AND
"|"
AND
If Field 4 = ABC:
If Field 5 is Null:
"Sometext"
Else:
"Someothertext" + Field 5
Else:
I entered the results in Field 6 as an example
Field 1 | Field 2 | Field 3 | Field 4 | Field 5 | Field 6 |
---|---|---|---|---|---|
611 | from July 1 | April to November | TextWith_äöü | from July 1 | Sometext | |
612 | from July 1 | April to November | ABC | TextWith_äöü | from July 1 | Someothertext TextWith_äöü |
612 | from July 15 | April to November | ABC | from July 15 | Someothertext | |
617 | from July 1 | April to November | ABC | April to November | Someothertext |
Up until now, I exported the table and calculated the value with some "when"-statements in Excel. But since I'd like to have the results in GIS i searched for an other solution.
I ended up using "arcpy.CalculateField_management" and something like this:
def compare(class1, class2, class3):
if class1 in (612, 611):
return class2
elif class1 == 617:
return class3
else:
return class1
# Expression below
compare(!some_field!, !another_field!, !another_field2!)
This didn't work quite well because
- the code will become huge (I have more fields and values to compare)
- there seem to be problems with converting/using characters which don't fit into ASCII
- i couldn't figure out how to ask properly if Field 5 is Null
- I could not properly translate the "AND" and the "OR" from Excel to Python (for example: If Field 4 is Null AND Field 5 is Null AND Field 1 is 612, Field 6 = ...)
-...
Is there an other, easyer solution how I can calculate Field 6 value?
Thanks a lot for your help!
Just to double check, the responses from arcpy.CalculateField_management - compare: how to return fieldvalues got you a working answer, you just have concerns about whether it is functional or optimal if scaled up?
Addressing some of your concerns:
- "the code will become huge" not because of Python itself or the structure of the suggestions people provided in the referenced thread, the code will become huge because the logic is nested and you want to apply it to more and more fields.
- Python works fine with Unicode, in fact the default encoding for strings in Python 3.x is UTF-8. What specific issues are you having?
- Regarding NULL, Python packages typically interpret/translate it as None, and this includes Esri tools. var is None is the general syntax.
- AND and OR are implemented the same in Python as in all other programming languages. In fact, Python has some really nice functions to simplify logical checks. Your partial example above is implemented as:
fld4 is None and fld5 is None and fld6 == 612
In Python, just like in SQL and many other languages, "is" is reserved for singleton checking while the equality operator is used for checking values. For example, the syntax is fld6 == 612 and not fld6 is 612.
Since the logic is incomplete, I can't say the following is exactly what you want, but it does reproduce Field 6 in your sample table:
def combine(fld1, fld2, fld3, fld4, fld5):
part1 = (
fld3
if fld1 == 617
else fld2
)
part2 = (
(
u"Sometext"
if fld5 is None
else u"Someothertext" + fld5
)
if fld4 == u"ABC"
else u"Sometext"
)
return u"{} | {}".format(part1, part2)
# Expression below
combine(!field1!, !field2!, !field3!, !field4!, !field5!)
Hey Joshua
Thank you a lot for all of your help!
After several hours of code typing, (at least in my opinion / compared to the excel-code) a kind of large code and several things not working (properly), I asked myself if there might be an easyer way to write the code. That's why I started thinking if I'm actually really using the easyest way to do it and therefore I opened this new thread.
I'm not sure if that makes a difference: I'm using ArcGIS 10.3 with python 2.7.8.
I imported my example-table as a table to a GDB and run your code. It did not work:
"Messages
Executing: CalculateField Tabelle Field_6 compare(!Field_1!, !Field_2!, !Field_3!, !Field_4!, !Field_5!) PYTHON_9.3 "def combine (fld1, fld2, fld3, fld4, fld5):\n part1 = (\n fld3 \n if fld1 == 617\n else fld2\n )\n part2 = (\n (\n u"Sometext"\n if fld5 is None\n else u"Someothertext" + fld5\n )\n if fld4 == u"ABC"\n else u"Sometext"\n )\n\n return u"{} | {}".format(part1, part2)"
Start Time: Thu Dec 06 11:04:19 2018
ERROR 000539: Error running expression: compare(612.0, u"from July 1", u"April to November", u"ABC", u"TextWith_äöü")
Traceback (most recent call last):
File "<expression>", line 1, in <module>
TypeError: compare() takes exactly 3 arguments (5 given)
Failed to execute (CalculateField).
Failed at Thu Dec 06 11:04:19 2018 (Elapsed Time: 0.02 seconds)"
I can't figure out why it thinks that not all the arguments would be used...?
Anyway, I tried to simplify my code based on your model.
This works perfectly:
def compare(Code, SchnittZP, WeideZP, NHG_YN):
part1 = (
"-"
if Code in (921, 922, 923, 924)
else "ERROR"
)
return part1
then I tried to enter an other argument (line 6+7) - resulting in an error "ERROR 000989: Python syntax error: Parsing error SyntaxError: invalid syntax (line 7) Failed to execute (CalculateField). ":
def compare(Code, SchnittZP, WeideZP, NHG_YN):
part1 = (
"-"
if Code in (921, 922, 923, 924)
"Text 634"
elif Code == 634
else "Wrong code"
)
return part1p
So I thought, maybe I need to adjust the whole code like this:
def compare(Code, SchnittZP, WeideZP, NHG_YN):
part1 = (
if Code in (921, 922, 923, 924):
"-"
elif Code == 634:
"Text 634"
else:
"Wrong code"
)
return part1
because I've never seen the order you put the result bevore the condition. (What's the difference? Why do you prefer result bevore condition? How can you enter en elif-statement?)
Anyway it gives back following error: "Runtime error Traceback (most recent call last): File "<string>", line 56, in <module> File "c:\program files (x86)\arcgis\desktop10.3\arcpy\arcpy\management.py", line 3453, in CalculateField raise e ExecuteError: Failed to execute. Parameters are not valid. ERROR 000989: Python syntax error: Parsing error SyntaxError: invalid syntax (line 4) Failed to execute (CalculateField). "
I tried to handle this by changing row 4 to
value = "-"
and in the end "return value" but it didn't change anything.
Thanks for the other useful hints about "my concerns"!
I will try to implement some of your hints and explain my problems with unicode later 🙂
Looking at your error message:
"Messages
Executing: CalculateField Tabelle Field_6 compare(!Field_1!, !Field_2!, !Field_3!, !Field_4!, !Field_5!) PYTHON_9.3 "def combine (fld1, fld2, fld3, fld4, fld5):\n part1 = (\n fld3 \n if fld1 == 617\n else fld2\n )\n part2 = (\n (\n u"Sometext"\n if fld5 is None\n else u"Someothertext" + fld5\n )\n if fld4 == u"ABC"\n else u"Sometext"\n )\n\n return u"{} | {}".format(part1, part2)"
Start Time: Thu Dec 06 11:04:19 2018
ERROR 000539: Error running expression: compare(612.0, u"from July 1", u"April to November", u"ABC", u"TextWith_äöü")
Traceback (most recent call last):
File "<expression>", line 1, in <module>
TypeError: compare() takes exactly 3 arguments (5 given)Failed to execute (CalculateField).
Failed at Thu Dec 06 11:04:19 2018 (Elapsed Time: 0.02 seconds)"
My function is called "combine" and takes 5 inputs, you called "compare." You need to update your expression field to call the correct function.
Your psuedo code, example data, and test code all have differences and some of it appears incomplete. It's impossible to accurately determine what exactly your logic needs to be so here are some tips:
Thank your for all those tips!
Concerning 3. str.format: is there a way to put together two strings and when one of them is "NULL/empty", ignore it and only take the "not empty" string?
Yes, but it also might be easier to use a generator expression with str.join:
>>> string_list = ["Hello", None, ",", None, "Goodbye"]
>>> "".join(s for s in string_list if s)
'Hello,Goodbye'
>>>
Excel To Table—Conversion toolbox | ArcGIS Desktop
might be a better option if most of you work is done there and python isn't in your comfort realm just yet
Is there a way to convert the code from excel to arcgis? Because if not I will have to export the feature class-table to excel, apply the codes and join the new table to the feature class every time I change some data. That's what I try to avoid.