If statement with multiple conditions but only check others if first fails - python

I'm trying to test two conditions, but only want to check the second condition if the first one fails. One example could be:
if df is None or len(df) == 0:
# do something
I know I can use two seperate if statements or a try...except block. However, I want to know if there is a more elegant pythonic way of doing it or is two seperate if statements the only way.

or is a short-circuit operator in python 3. This means the second condition (here len(df) == 0) is executed only if the first one (here df is None) is false.

You can running your code like this:
if df == none:
# Do this
elif len(df) == 0:
# Do this
else:
# Do this
It works fine and can definately help

Related

Is it possible to have multiple conditions in a function which includes a for loop in Python?

I'm new to programming with Python. Currently, I'm working on a program/algorithm to determine maintenance (combined replacement of multiple items) based on these items their condition. To be precise, I want to replace these items when one item's condition is below a predetermined threshold (for example 10%). The problem I have with my code, see below, is when this threshold is met all items are replaced.
def maintenance_action(self):
do_repair = False
for i in item:
if i.condition[-1] <= 10:
do_repair = True
break
if do_repair:
for i in items:
i.repair()
However, I want to include an additional threshold (let's say 50%) which excludes all items with a condition > 50% from the maintenance action. It is important that the first threshold is met (because this item must be replaced) before the second one 'kicks in' (the items I want to include). I hope someone can help me.
Thanks!
The simplest way would be to call repair right away, and not use a flag at all:
for i in items:
if i.condition[-1] <= 10:
i.repair()
Or, if you can't do that, you could build a list of items to be repaired in the first loop, and then process that list later:
items_to_repair = []
for i in item:
if i.condition[-1] <= 10:
items_to_repair.append(i)
# other code here
for i in items_to_repair:
i.repair()
If do_repair is set to True in the for loop when the condition is met, all the variables are repaired in the second loop. In order to prevent this, you should repair the items which are met to the condition in the first loop. So I think there is no need to use the do_repair variable and the second for loop in this case.
def maintenance_action(self):
for i in item:
if i.condition[-1] <= 10:
i.repair()

Weird behavior when checking for NaNs in a pandas dataframe

I want to loop over all the rows in a df, checking that two conditions hold and, if they do, replace the value in a column with something else. I've attempted to do this two different ways:
if (sales.iloc[idx]['shelf'] in ("DRY BLENDS","LIQUID BLENDS")) & np.isnan(sales.iloc[idx]['traceable_blend']):
sales.iloc[idx]['traceable_blend'] = False
and:
if (sales.iloc[idx]['shelf'] in ("DRY BLENDS","LIQUID BLENDS")) & (sales.iloc[idx]['traceable_blend'] == np.NaN):
sales.iloc[idx]['traceable_blend'] = False
By including print statements we've verified that the if statement is actually functional, but no assignment ever takes place. Once we've run the loop, there are True and NaN values in the 'traceable_blend' column, but never False. Somehow the assignment is failing.
It looks like this might've worked:
if (sales.iloc[idx]['shelf'] in ("DRY BLENDS","LIQUID BLENDS")) & np.isnan(sales.iloc[idx]['traceable_blend']):
sales.at[idx, 'traceable_blend'] = False
But I would still like to understand what's happening.
This, sales.iloc[idx]['traceable_blend']=False, is index chaining, and will almost never work. In fact, you don't need to loop:
sales['traceable_blend'] = sales['traceable_blend'].fillna(sales['shelf'].isin(['DRY BLENDS', 'LIQUID BLENDS']))
Pandas offers two functions for checking for missing data (NaN or null): isnull() and notnull() - They return a boolean value. I suggest to try these instead of isnan()
You can also determine if any value is missing in your series by chaining .values.any()

Python leave multiple if statements [duplicate]

This question already has answers here:
"if", and "elif" chain versus a plain "if" chain
(2 answers)
Closed 8 years ago.
grid = 0
if grid == 0:
grid == 1
print("grid 0")
elif grid == 1:
print("grid 1")
grid == 2
When first if statement is true, the second will become true as well.
Is there a statement, to skip the whole if structure otherwise i would have to split the if functions which would double the if statements.
First of all, grid == 1 will not change the value of grid; it's only comparing it to 1, obtaining a boolean value and then immediately throwing it away by not using it. To change the value of a variable, you need to use the assignment operator = (as opposed to the equality comparison operator ==): for example grid = 1.
Also, there's nothing bad with using more if-s it it makes sense. In fact, I would recommended making your program work with as simple and straightforward logic as possible first before trying to "optimize" it or make it more compact.
Also, I would say modifying the value of a variable WHILE you are in the process of testing that variable using a chain of if-elif-else, is considered bad style because it makes your code more complicated and hard to reason about (to yourself and to others).
And in any case, if the first if "fails", any subsequent elifs will not even be looked at, so basically you're forced to use multiple ifs anyway in this case.
As a bonus to get you inspired (and maybe even start reading something like http://learnpythonthehardway.org), here's a demonstration of how = and == could also be used together:
# set `is_wet` to `True` if `precipitation` is "raining", otherwise `False
is_wet = (precipitation == "raining")
The second statement will be skipped alone because you used elif instead of a second if.
if condition_a:
statement_a
elif condition_b:
statement_b:
else:
default_statement
Only one of these conditions will EVER activate. In the case of:
if i > 1:
do_stuff
elif i > 1000:
do_bigger_stuff
if i==2000, only the first statement will execute (do_stuff, not do_bigger_stuff)
Be aware in your example that grid == 1 will not set grid to 1, it will just evaluate False :)

How to get a loop in python to skip one iteration in the loop when it encounters a cell with a particular input? See below.

I have a program that pretty much consists of a simple loop that goes through a bunch of numbers that are arranged in a column (among many other columns in the spreadsheet) and it consists of a bunch of if-statements that check if each number is within a particular range and based on which range it falls into, it will perform a specific task.
However, the problem is that, every now and then, some of the cells in the column will just contain a "-" symbol and won't have any numbers and the program just stops there, since it can't compare the dash sign to the ranges of numbers I'm making my if-statement comparisons to. What's the best way to just skip over these types of cells? I can't delete those cells because I've got like 100,000+ rows and there are other columns in the spreadsheet that are of use to me. I tried using the break and continue function but for some reason the program just doesn't read it as such.
for x in range(1,1000):
if value[x] == "-":
break # I tried this with the continue function as well
Either of these will work:
for x in range(1,1000):
if value[x] == "-":
pass
else:
# do work
or
for x in range(1, 1000):
if value[x] == "-":
continue
# do work
Note that the indentation is crucial to make the right things happen at the right time.
break in Python is like exit for and exit while from other languages; it ends the loop, rather than skipping one item.
for x in range(1, 1000):
if value[x] == '-': continue
doImportantThings ()
for x in range(1,1000):
if value[x] == "-":
continue
I prefer it to else because you avoid extra indent - each indent makes code fragment less readable, the longer the fragment - the worth
It could also be a problem of not getting complete match in your comparison.
ie. if the string in value[x] = "- " then value[x] == "-" will be false.
try this:
for x in range(1,1000):
# this will be true if there is a '-' in the string at all
if "-" in value[x]:
continue
Note that this approach might give false positives in the event that you have valid cells that just happen to contain a -.

Quick Sort using Python

I was wondering if someone can help me to fix the error my code for quick sort has:
It does not compile and highlights the last line of the code in red.
I can not figure out what is wrong. sort is already defined as a function so why is it highlighted as red?
def sort(*myarray):
less = []
equal = []
greater = []
if len(myarray) > 1:
pivot = myarray[0]
for x in myarray:
if x < pivot:
less.append(x)
if x == pivot:
equal.append(x)
if x > pivot:
greater.append(x)
return sort(less)+sort(equal)+sort(greater)
else:
return myarray
print sort([12,4,5,6,7,3,1,15])
You're defining the function as taking a variable number of arguments (the *myarray bit), but then using myarray inside as a single argument (the list to sort), when it is a list containing the list to sort.
You probably should remove the * from your function parameter. This questions esplains it quite thoroughly.
You could keep the *, but then you would have to play a bit with tuple unpacking to get the same result.
edit
Although the above is true, this might not be the issue you're encountering.
IDLE will give you the invalid syntax error on the ast line, because in interactive mode - with lines starting with >>>, it accepts only one statement at a time. In your case that statement is the sort() definition.
Try hitting enter 2 times after the function definition, this should get you back to the repl, where you can introduce another statement (print sort([12,4,5,6,7,3,1,15]))
There are a couple things wrong which makes me curious how you are testing this:
Python code is not "compiled", it is interpreted. (Okay, not precisely true; it's parsed into a sort of byte-code; still, it's not compiled in the same sense as a language such as C, where the entire program has to be converted into machine instructions before any of it can be run.) Also you mention the last line of code is highlighted in red -- by what?
This code actually works, but only if you remote the star/asterisk in front of myarray in def sort(*myarray):. Otherwise it actually returns a single-element tuple containing the original array.
Assuming you have two or more elements that equal a pivot at some point, you get an infinite loop, because you will get: equal = [x,x] (two elements at least), and then invoke sort([x,x]), which in its turn will take x as a pivot, and create equal = [x,x], and cause sort([x,x]), ....
Simple solution to this problem: What should be the output of the sort(equal)? How do you sort a list of identical elements?
Edit: Well, your comments show that you are looking for a different problem, but I'll leave it here because it explains a different issue you have with your code and should be solved.
If it is a function for quick sorting, can you really use the function sort in it?
Wouldn't something like this work?
def qsort(list):
pivind=0
left, right, pivot= [], [], []
for x in list:
if list[pivind]==x: pivot.append(x)
elif list[pivind]>x: left.append(x)
else: right.append(x)
if len(left)>1: left=qsort(left)
if len(right)>1: right=qsort(right)
return (left + pivot + right)

Categories

Resources