Cleaner way to do if else on multiple variables in Python - python

i have 4 variables here that needs to check whether its true or false. together will all the combinations.. 4 true, 3 true 1 false, 2 true 2 false, 1 true 3 false and all false.. in total this will make like 10++ condition (a bit lazy to count).
if game and owner and platform and is_new and for_sale:
game_copy = GameCopy.objects.all()
elif game:
game_copy = GameCopy.objects.filter(game=game)
elif platform:
game_copy = GameCopy.objects.filter(platform=platform)
elif owner:
game_copy = GameCopy.objects.filter(user=owner)
elif is_new:
game_copy = GameCopy.objects.filter(is_new=is_new)
elif for_sale:
game_copy = GameCopy.objects.filter(for_sale=for_sale)
else:
game_copy = GameCopy.objects.all()
return game_copy
im looking for a leaner approach for this condition.. hopefully ended with something with 5 to 10 lines

You could add everything that's truthy to a dictionary and then pass those to the function by unpacking keyword arguments.
args = { "game": game, "owner": owner, "platform": platform, "is_new": is_new, "for_sale": for_sale }
# check if all args are truthy
all_args = all(v for v in args.values())
# filter out only the truthy args
filtered_args = {k: v for k, v in args.items() if v}
if all_args or not filtered_args:
# if all_args is true or filtered_args is empty
game_copy = GameCopy.objects.all()
else:
# Unpack filtered_args into filter()
game_copy = GameCopy.objects.filter(**filtered_args)

You could change your variable to a set of flags (bits set in a unique integer)
GAME = 1 << 0 # 1
OWNER = 1 << 1 # 2
PLATFORM = 1 << 2 # 4
IS_NEW = 1 << 3 # 8
FOR_SALE = 1 << 4 # 16
# for instance flags = GAME
# or flags = OWNER | IS_NEW
# ensures that there is only one flag set and pass it to you filter
if (flags & (flags-1) == 0) and flags != 0:
game_copy = GameCopy.objects.filter(flags)
# Otherwise
else: game_copy = GameCopy.objects.all()
return game_copy

Related

How to set variable value to be a new row python

My code:
test_str = '''
(()(code)())
((t(e(x(t(()
()(co)de)('''
countofrightbrackets = 0
countofleftbrackets = 0
blockcount = 0
myDict = {};
for i in test_str:
if i == '(':
countofrightbrackets = countofrightbrackets + 1
if i == ')':
countofleftbrackets = countofleftbrackets + 1
if i == '':
blockcount = blockcount + 1
if countofrightbrackets == countofleftbrackets:
myDict.update({blockcount:'True'});
else:
myDict.update({blockcount:'False'});
print (myDict)
My program is counting () and if count of ( = ) then save to dictionary True. Else false. In test_str I have some blocks - they are dissociated with 2 new rows. In if i == '': I want to show, that if I = 2 new rows, then compete the code. Also I need to check are brackets are at correct positions - like ()()() is true and ())( is false. How to do this?
Example:
Input:
(()()())
((((((()
()())(
Output:
1: True 2: False 3: False

Improve python code with many if statements

I've seen a code on a project and would like to know how to write a code with less statements.
Here is the code:
if not self.test_done:
phase = "Test"
else:
if self.need_video and not self.video_sent:
phase = 'Video'
else:
if not self.screening1_made and not self.screening2_made:
phase = 'Screening 1'
else:
if ( self.screening1_made and not self.screening2_made ) or not self.passed_screening:
phase = 'Screening 2'
else:
if not self.passed_phase1:
phase = 'Interview 1'
else:
if not self.passed_phase2:
phase = 'Interview 2'
else:
if not self.passed_phase3:
phase = 'Interview 3'
else:
if not self.got_offer:
phase = 'Waiting offer decision'
else:
if self.accepted_offer is None:
phase = 'Waiting decision from candidate'
elif self.accepted_offer == "Accepted":
phase = 'Accepted offer'
elif self.accepted_offer == "Declined":
phase = 'Declined offer'
What would be best practices to avoid nested if statements?
You can extract it to the method and early return, also you can use a dictionary lookup to get your output.
OFFER = {
None: "Waiting decision from candidate",
"Accepted": "Accepted offer",
"Declined": "Declined offer",
}
def some_function_name(self):
if not self.test_done:
return "Test"
if self.need_video and not self.video_sent:
return "Video"
if not self.screening1_made and not self.screening2_made:
return "Screening 1"
if (self.screening1_made and not self.screening2_made) or not self.passed_screening:
return "Screening 2"
if not self.passed_phase1:
return "Interview 1"
if not self.passed_phase2:
return "Interview 2"
if not self.passed_phase3:
return "Interview 3"
if not self.got_offer:
return "Waiting offer decision"
return OFFER.get(self.accepted_offer, None)
This smells to me like a state machine. A "switch - case" construct is often used when evaluating state machines, and while python doesn't currently have that exact feature yet (3.10 will introduce match: case), A list of elif's should do the trick just fine:
if not self.test_done:
phase = "Test"
elif self.need_video and not self.video_sent:
phase = 'Video'
elif self.need_video and not self.video_sent:
phase = 'Video'
elif not self.screening1_made and not self.screening2_made:
phase = 'Screening 1'
elif ( self.screening1_made and not self.screening2_made ) or not self.passed_screening:
phase = 'Screening 2'
elif not self.passed_phase1:
phase = 'Interview 1'
elif not self.passed_phase2:
phase = 'Interview 2'
elif not self.passed_phase3:
phase = 'Interview 3'
elif not self.got_offer:
phase = 'Waiting offer decision'
elif self.accepted_offer is None:
phase = 'Waiting decision from candidate'
elif self.accepted_offer == "Accepted":
phase = 'Accepted offer'
elif self.accepted_offer == "Declined":
phase = 'Declined offer
flattened it's not so bad to look at, and you probably won't find a significantly more elegant solution without changing how you track all the conditionals.
You should refactor your program. Here's a rough Interview class and related objects, which includes a basic dictionary for event names and number of rounds.
class InterviewEvent:
def __init__(self, event_id, event_name, total_rounds) -> None:
self.event_id: int = event_id
self.event_name: str = event_name
self.total_rounds: int = total_rounds
self.competed_rounds: int = 0
self.completed: bool = False
class Interview:
"""Interview class to track interview progress.
"""
def __init__(self, expected_workflow: dict = None):
self.events = []
self.current_event: InterviewEvent = None
if expected_workflow:
self.__init_events(expected_workflow)
def __init_events(self, wf: dict) -> None:
"""Populate events list from workflow dictionary."""
self.events = [InterviewEvent(i, k, v) for i, (k, v) in enumerate(wf.items())]
# Set current event
self.current_event = self.events[0]
def completed_event_round(self, title, round_number):
"""Update round number for event. If complete, increment
to next round or next event in workflow.
"""
for event in self.events:
if event.event_name.lower() == title.lower():
if event.competed_rounds < round_number:
event.competed_rounds = round_number
# Mark event completed if completed rounds equals total rounds.
if event.competed_rounds == event.total_rounds:
event.completed = True
if event.completed:
# Increment current event by 1.
self.current_event = self.events[event.event_id + 1]
def __event_attrs(self, e: InterviewEvent) -> str:
return "\n".join([f"{k}: {v}" for k, v in e.__dict__.items()])
#property
def view_current(self):
print(self.__event_attrs(self.current_event))
#property
def remaining_events(self):
return [e for e in self.events if not e.completed]
#property
def view_remaining_events(self):
events_remaining = self.remaining_events
if events_remaining:
print("\n\n".join([self.__event_attrs(e) for e in events_remaining]))
#property
def event_ids(self):
"""Return all current event IDs."""
return [e.event_id for e in self.events]
#property
def event_names(self):
"""Return all current event names."""
return [e.event_name for e in self.events]
# Dictionary of event names and number of rounds.
workflow_rounds = dict(
Test = 1,
Video = 1,
Screening = 2,
Interview = 3,
)
View events that are not complete.
interview.view_remaining_events
Output:
event_id: 0
event_name: Test
total_rounds: 1
competed_rounds: 0
completed: False
event_id: 1
event_name: Video
total_rounds: 1
competed_rounds: 0
completed: False
event_id: 2
event_name: Screening
total_rounds: 2
competed_rounds: 0
completed: False
event_id: 3
event_name: Interview
total_rounds: 3
competed_rounds: 0
completed: False
View current event
interview.view_current
Output:
event_id: 0
event_name: Test
total_rounds: 1
competed_rounds: 0
completed: False
Mark first Test round as complete
interview.completed_event_round(title = "Test", round_number = 1)
Again, view events that are not complete.
interview.view_remaining_events
Output:
event_id: 1
event_name: Video
total_rounds: 1
competed_rounds: 0
completed: False
event_id: 2
event_name: Screening
total_rounds: 2
competed_rounds: 0
completed: False
event_id: 3
event_name: Interview
total_rounds: 3
competed_rounds: 0
completed: False
Finally, view current event
interview.view_current
Output:
event_id: 1
event_name: Video
total_rounds: 1
competed_rounds: 0
completed: False
You can use lambda to run expressions. In the example below, we itterate through the list of tuples, containing lambda expressions and strings. When we find a lambda expression that is true, we break out of the loop.
x = 1
expressions = [
(lambda: x == 0, 'X is equal to 0'),
(lambda: x == 1, 'X is equal to 1'),
(lambda: x == 2, 'X is equal to 2'),
]
phrase = 'No result found'
for item in expressions:
expression = item[0]
text = item[1]
if expression():
phrase = text
break
print(phrase)
This is the result.
X is equal to 1

Writing a function which accepts two strings and returns True in python 3

Write a python function, check_anagram() which accepts two strings and returns True, if one string is an anagram of another string. Otherwise returns False.
The two strings are considered to be an anagram if they contain repeating characters but none of the characters repeat at the same position. The length of the strings should be the same.
Note: Perform case insensitive comparison wherever applicable.
This is my code:
def check_anagram(data1,data2):
first = data1.lower()
second = data2.lower()
d1 = []
d2 = []
for i in range(0, len(first)):
d1.append(first[i])
for i in range(0, len(second)):
d2.append(second[i])
for_check1 = sorted(d1)
for_check2 = sorted(d2)
if (for_check1 != for_check2):
return False
count = 0
if (len(d1) == len(d2)):
for i in d1:
for j in d2:
if(i == j):
a = d1.index(i)
b = d2.index(j)
if(a == b):
return False
else:
count += 1
if(count == len(first)):
return True
else:
return False
print(check_anagram("Schoolmaster", "Theclassroom"))
The output I am getting is "False"
Although this program is giving relevant output for string values like {silent, listen}{Moonstarrer, Astronomer}{apple, mango} but not for the above two strings(in code)
What cases am I missing in this code?? How to rectify this thing?
Your function could be simplified as:
def check_anagram(data1, data2):
data1 = data1.lower()
data2 = data2.lower()
if sorted(data1) != sorted(data2):
return False
return all(data1[i] != data2[i] for i in range(len(data1)))
Which actually works for the case you specified.
your code is correct just write len(second) instead of count.
def check_anagram(data1,data2):
first = data1.lower()
second = data2.lower()
d1 = []
d2 = []
for i in range(0, len(first)):
d1.append(first[i])
for i in range(0, len(second)):
d2.append(second[i])
for_check1 = sorted(d1)
for_check2 = sorted(d2)
if (for_check1 != for_check2):
return False
count = 0
if (len(d1) == len(d2)):
for i in d1:
for j in d2:
if(i == j):
a = d1.index(i)
b = d2.index(j)
if(a == b):
return False
else:
count += 1
if(len(second) == len(first)):
return True
else:
return False
print(check_anagram("Schoolmaster", "Theclassroom"))
This program of mine is clearing all possible test cases.
def check_anagram(data1,data2):
data1=data1.lower()
data2=data2.lower()
if(len(data1)==len(data2)):
if(sorted(data1)!=sorted(data2)):
return False
else:
if(data1[i]!=data2[i] for i in range(len(data1))):
return True
else:
return False
else:
return False
print(check_anagram("eat","tea"))

In a nested if loop, how to return true for multiple matching conditions?

In the below program, even though all the if conditions are matching, it returns true just once. How do i make it return true and print as many times as the conditions match?
lotto_numbers = [1,1,1]
fireball_number = 1
user_input1 = user_input2 = user_input3 = 1
def fbcheck():
if lotto_numbers == [user_input1,user_input2,fireball_number]:
return True
elif lotto_numbers == [fireball_number, user_input2, user_input3]:
return True
elif lotto_numbers == [user_input1, fireball_number, user_input3]:
return True
else:
return False
if (fbcheck() == True):
print ('you won')
You can use all:
def fbcheck():
user_data = [user_input1,user_input2,fireball_number]
lotto_numbers = [1,1,1]
print([a==b for a, b in zip(lotto_numbers, user_data)])
return all(a==b for a, b in zip(lotto_numbers, user_data))
print(fbcheck())
Output:
[True, True, True]
True

Debugging a function that tries to merge two strings but sometimes does not return

The function is supposed to return True if the parameter s can be formed solely from the parameters part1 and part2, and returns False otherwise. My function works when it is supposed to return True, but when False, it doesn't return anything at all.
def is_merge(s, part1, part2):
list = []
v1 = 0
v2 = 0
i = 0
while i < len(s):
if v1 < len(part1) and s[i] == part1[v1] :
list.append(s[i])
i += 1
v1 += 1
elif v2 < len(part2) and s[i] == part2[v2] :
list.append(s[i])
i += 1
v2 += 1
list = ''.join(list)
if list == s:
return True
else:
return False
right = (is_merge('codewars', 'cdw', 'oears'))
wrong = (is_merge('codewarse', 'cdw', 'oears'))
if right == True:
print("true")
if wrong == False:
print("false")

Categories

Resources