Python accumulative conditional logic - python

I am struggling with the logic for the problem below and I know that even if I nailed the logic, I would probably implement it clumsily, so any advice would be awesome.
I have a dictionary representing a file:
the_file = {'Filename':'x:\\myfile.doc','Modified':datetime(2012,2,3),'Size':32412}
I have a list of filters and I want to filter the file dictionary to determine a match.
filters = [
{'Key':'Filename','Criteria':'Contains','Value':'my'},
{'Key':'Filename','Criteria':'Does not end with','Value':'-M.txt'},
{'Key':'Modified','Criteria':'After','Value':datetime(2012,1,1)}
]
My best attempt at creating a function to do this (which doesn't work):
def is_asset(the_file, filters):
match = False
for f in filters:
if f['Key'] == u'Filename':
if f['Criteria'] == u'Contains':
if f['Value'] in the_file['Filename']:
match = True
elif f['Criteria'] == u'Starts with':
if the_file['Filename'].startswith(f['Value']):
match = True
elif f['Criteria'] == u'Ends with':
if the_file['Filename'].endswith(f['Value']):
match = True
elif not f['Criteria'] == u'Does not end with':
if the_file['Filename'].endswith(f['Value']):
match = False
elif f['Criteria'] == u'Equals':
if os.path.basename(the_file['Filename']) == f['Value']:
match = True
elif f['Criteria'] == u'Does not contain':
if f['Value'] in the_file['Filename']:
match = False
elif f['Key'] == u'Modified':
mtime = int(os.path.getmtime(the_file['Filename']))
if f['Criteria'] == u'Before':
if f['Value'] > datetime.fromtimestamp(mtime):
the_file['Modified'] = mtime
match = True
elif f['Criteria'] == u'After':
if f['Value'] < datetime.fromtimestamp(mtime):
the_file['Modified'] = mtime
match = True
elif f['Key'] == u'Size':
size = long(os.path.getsize(the_file['Filename']))
if f['Criteria'] == u'Bigger':
if f['Value'] < size:
the_file['Size'] = size
match = True
elif f['Value'] > size:
the_file['Size'] = size
match = True
if match:
return the_file

Instead of trying to do it in one megafunction, break it down into smaller steps.
filenamecondmap = {
u'Contains': operator.contains,
u'Does not end with': lambda x, y: not x.endswith(y),
...
}
...
condmap = {
u'Filename': filenamecondmap,
u'Modified': modifiedcondmap,
...
}
And then walk the structures until you have the conditional, then execute it.
condmap[u'Filename'][u'Contains'](thefile['Filename'], 'my')

You can simply use functions as your 'criteria'. This makes it much simpler, as you don't have to write a big if-else ladder. Something like this:
def contains(value, sub):
return sub in value
def after(value, dt):
return value > dt
filters = [
{'Key': 'FileName', 'Criteria': contains, 'Value': 'my'},
{'Key': 'Modified', 'Criteria': after, 'Value': datetime(2012,1,1)}
]
for f in filters:
if f['Criteria'](filename[f['Key']], f['Value']):
return True

Related

A more pythonic way to check for duplicate characters and check that they are next to each other?

Is there a more pythonic way to check if there are two '((' AND '))' in the string? I've made an attempt but it does not look very pythonic
def check (string):
text = list(string)
prev = text[0]
curr = text[1]
first=False
second=False
for nxt in text[2:]:
if (prev == "(" and curr == "("):
first = True
elif (curr == "(" and nxt == "("):
first = True
elif (prev == ")" and curr == ")"):
second = True
elif (curr == ")" and nxt == ")"):
second = True
prev = curr
curr = nxt
if (first == True and second == True):
return "true"
else:
return "false"
examples:
check("((a)) + b") # true
check("((a) + b") # false
check("(a+b))") # false
check("((a+b))") # true
check("((a)(b))") # true
check("(((a)))") # true
check("a)) + ((b") # true
If all you want is "has adjacent parens of each type", the solution is just:
def check(string):
return '((' in string and '))' in string
A regex could be used to confirm they appear in the correct order and reduce the work to a single pass over string, not two, but if you don't need correct "logical" order, the incremental work of scanning twice is pretty meaningless 99% of the time. A regex solution would just be:
import re
def check(string):
return re.search(r'\(\(.*\)\)', string, re.DOTALL) is not None

Optimize the code for dataframes in python

Below is the code for checks on two columns. I know this isn't the proper way of doing it on two columns of a dataframe but I was hoping to get help for doing it in a better way
for i in range(len(df)):
if df['Current_Value'][i].lower() == 'false'or df['Current_Value'][i].lower() == '0' and df['_Value'][i].lower() == 'false' or df['_Value'][i].lower() == '0':
df['CHECK'][i] = True
elif df['Current_Value'][i].lower() == 'true' or df['Current_Value'][i].lower() == '1' and df['_Value'][i].lower() == 'true' or df['_Value'][i].lower() == '1':
df['CHECK'][i] = True
elif df['Current_Value'][i].lower() in df['_Value'][i].lower():
df['CHECK'][i] = True
else:
df['CHECK'][i] = False
You should use lambda expressions for such a check. Although you haven't provided us with a sample dataset, what you could do is something like this:
First define the lambda function
def fill_check_column(current_value, value):
# Precompute this, so that it is calculated only once
current_value = current_value.lower()
value = value.lower()
if current_value in ['false', '0'] and value in ['false', '0']:
return True
elif current_value in ['true', '1'] and value in ['true', '1']:
return True
elif current_value in value:
return True
else:
return False
Then use it on the data frame:
df['Check'] = df.apply(lambda row: fill_check_column(current_value=row['Current_Value'],
value=row['_Value'],
axis=1)
You could also improve the fill_check_column to make the checks only once.

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

python comparing parentheses from user input and making sure they have a pair

I'm writing a program to take a user input of parentheses i.e. {} [] () and checking to see if they have a pair (opening and closing). I'm running into an error when running my code where i always get the return false. I've tried different ways of checking against a pre set "list" but it doesn't seem to work. I have to use the class from above too. any help is appreciated.
some example inputs are:
>>>parenthesesMatch('{[]}')
True
>>>parenthesesMatch('({})')
True
>>>parenthesesMatch('{[)]}')
False
My code:
#George flamburis
class Stack():
def __init__(self,que=[]):
self.lst = que
def __repr__(self):
return "Stack({})".format(self.lst)
def push(self, add):
self.lst.append(add)
def pop(self):
return self.lst.pop()
def isEmpty(self):
return self.lst==[]
def first(self, loc=0): #naming of this method can't be []
return self.lst[loc]
def len(self):
return len(self.lst)
def parenthesesMatch(match):
s = Stack()
end = []
for char in match:
if char in "[ { (":
s.push(char)
else:
end.append(char)
if s.len()==len(end):
for num in range(len(end)):
if s.first(num) and end[num] not in '[]' or '{}' or'()':
return False
return True
elif s.len()!=len(end):
return False
It's much easier to simply attempt to pop a closing character off the stack when you see one, and fail if that isn't possible.
pairs = dict(tuple(pair) for pair in ["()", "[]", "{}"])
# pairs["("] == ")"
# pairs["["] == "]"
# etc
def parenthesesMatch(match):
s = Stack()
for char in match:
# Not "] } )"
if char in pairs.values() and pairs[s.pop()] != char:
return False
elif char in pairs:
s.push(char)
return s.isEmpty()
def match(par):
combs = {'{': '}', '(': ')', '[': ']'}
stack = []
for char in par:
if char in '[{(':
stack.append(char)
elif char == combs[stack[len(stack) - 1]]:
stack.pop()
else:
return False
return len(stack) == 0
Comments outline my thought.
def isParenthesesMatch(s):
# to be balanced should be divisable by 2
if len(s)%2 != 0:
return False
open_paren = ['(','[','{']
open_paren_stack = list()
match_close_paren = {')' : '(',']': '[', '}' : '{'}
for item in s:
#Don't care about open
if item in open_paren:
open_paren_stack.append(item)
#if closed we should be able to pop
elif len(open_paren_stack) == 0:
return False
#if we can pop it should match up
elif open_paren_stack.pop() != match_close_paren[item]:
return False
#in case we push a bunch of open and then end with balanced pair
return len(open_paren_stack) == 0
def parenthesesMatch(match):
counter = {'{': 0, '[': 0, '(': 0, '}': 0, ']': 0, ')': 0}
parantheses = '{}[]()'
for character in match:
if character not in parantheses:
continue
counter[character] += 1
return (counter['{'] == counter['}']) and (counter['['] == counter[']']) and (counter['('] == counter[')'])

Python serial checks refactoring

Ho can this code be optimized?
Maybe it is possible to write it shorter, make it more 'pythonic'?
...
check_pass = 0
if key == 'media':
size_check_pass = 0
if some_check_func(xxx): size_check_pass = 1
...
format_checks_pass = 0
if...some_checks... : format_checks_pass = 1
if size_check_pass and format_checks_pass: check_pass = 1
if key == 'text':
line_end_check_pass = 0
if (((some checks))): line_end_check_pass = 1
lenght_check_pass = 0
if len(file) < 1000: lenght_check_pass = 1
if line_end_check and lenght_check_pass: check_pass = 1
if check_pass:
...
The background of the code is to check each file type for different conditions.
You could use a dictionary as a sort of dispatch table perhaps. Something like
def media_checks(f):
...
return pass
def text_checks(f):
...
return pass
_dispatch = {}
_dispatch['media'] = media_checks
_dispatch['text'] = text_checks
dispatch_func = _dispatch[key]
check_pass = dispatch_func(your_file)
This would split you code up so it is easier to read and maintain. It also isolates the code for checking each file type in an individual function.
First, for your first if, your code suffers from conditional complexity code smell. You can fix with inline method refactoring: you don't need your size_check_pass and format_checks_pass booleans, and can evaluate both conditions directly in the final if statement, with if ...some_checks... and some_check_func(xxx) instead of if size_check_pass and format_checks_pass. which gives you
check_pass = 0
if key == 'media':
if ...some_checks... and some_check_func(xxx):
check_pass = 1
Then, do this for the second if also. And you don't want to check if key = 'text' if you had already that key = 'media', so in the end
check_pass = 0
if key == 'media':
if some_check_func(xxx)and ...some_checks...:
check_pass = 1
else if key == 'text':
if (((some checks)))and len(file) < 1000:
check_pass = 1
if check_pass:
...
So you always have a sequence of checks.
First, you can shorten your conditions:
...
check_pass = False # to make it more boolean
if key == 'media':
size_check_pass = some_check_func(xxx)
format_checks_pass = ...result of your checks...
check_pass = size_check_pass and format_checks_pass
if key == 'text':
line_end_check_pass = (((some checks)))
length_check_pass = len(file) < 1000
check_pass = line_end_check and length_check_pass
if check_pass:
...
or compress them even more:
...
check_pass = False # to make it more boolean
if key == 'media':
check_pass = some_check_func(xxx) and ...result of your checks...
if key == 'text':
check_pass = (((some checks))) and len(file) < 1000
if check_pass:
...
And then you could apply a system like the one from jamesj, but maybe with lists of conditional expressions:
def some_checks():
...
return True or False
def other_checks(f):
...
return ...
_dispatch = {
'media': [lambda: some_check_func(xxx), some_checks],
'text' : [other_checks, lambda: len(file) < 1000]
}
dispatch_list = _dispatch[key]
check_pass = all(func() for func in dispatch_list)

Categories

Resources