Python if statement: False vs. 0.0 - python

Is it possible to:
for k,v in kwargs.items()
if v == None or v == '' or v == 1.0 or v == False:
del kwargs[k]
without deleting the key if v == 0.0? (False seems to equal 0.0), and without deleting the keys who equal True.

Or you can put it like this :
if v in (None, '', 1.0) or v is False:

You should use v is False instead of v == False. The same applies for your comparison to None. See PEP 8 - Style Guide for Python:
Comparisons to singletons like None should always be done with 'is' or 'is not', never the equality operators.

Slow down guys with your advice, from PEP 8:
Don't compare boolean values to True or False using ==
Yes: if greeting:
No: if greeting == True:
Worse: if greeting is True:
Also comparing float value you should not use == but
abs(x-other) < verysmall

Also you could use
if not v:
# do something
This may not be quite as precise as if v is False as it also runs for if v is 0, None, empty set etc.
I had trouble with this problem and the above solution worked for me.

Thanks for your replies. Using the suggestions, the problem was solved:
kwargs = {'None': None, 'empty': '', 'False': False, 'float': 1.0, 'True': True}
for k,v in kwargs.items():
if v in (None, '', 1.0) and v is not True:
del kwargs[k]
if v is False:
del kwargs[k]
kwargs
{'True': True}
-->
kwargs = {'None': None, 'empty': '', 'False': False, 'float': 0.0, 'True': True}
for k,v in kwargs.items():
if v in (None, '', 1.0) and v is not True:
del kwargs[k]
if v is False:
del kwargs[k]
kwargs
{'True': True, 'float': 0.0}

Related

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.

Attempting to call a specific name to a function

I'm feeling quite generally stupid at the moment.
I've been attempting to get my function to run a some code once a specific name has been inputted.
I feel as if the code I am putting together is quite childish and I'm currently trying to find some help on what I am doing wrong. Any input is appreciated. I apologise for my messy code.
I want to simply get my function argument (cond) to be able to run this specific code if its either inexpensive, large_screen or apple_product. Thanks for all your help :)
def satisfies(product, cond):
inexpensive = (4, '<=', 1000)
large_screen = (2, '>=', 6.3)
apple_product = (1, '==', 'Apple')
conditions = (inexpensive, large_screen, apple_product)
if cond == conditions[0]:
if cond[1] == '<=':
return True if cond[2] <= product[4] else False
elif cond[1] == '<=':
return True if cond[2] <= product[4] else False
elif cond[1] == '==':
return True if cond[2] == product[4] else False
if cond == conditions[1]:
if cond[1] == '<=':
return True if cond[2] <= product[4] else False
elif cond[1] == '<=':
return True if cond[2] <= product[4] else False
elif cond[1] == '==':
return True if cond[2] == product[4] else False
if cond == conditions[2]:
if cond[1] == '==':
return True if cond[2] == product[1] else False
Input : A product feature list (product() and a condition
(cond) as specified above.
Output: True if cond holds for the product otherwise False.
Calling satisfies(['Nova 5T', 'Huawei', 6.26, 3750, 497], inexpensive) should return True.
You can simplify your code by
splitting it into two functions:
one that checks a single condition
another that checks many using a combinator function; the default is all(), for "AND"; if you want, you can use combinator=any for an "OR" sort of query).
using the operator module, which contains predicate functions for various operators, and a mapping for your operator strings to those functions
import operator
operators = {
"<=": operator.le,
">=": operator.ge,
"==": operator.eq,
"!=": operator.ne,
"<": operator.lt,
">": operator.gt,
}
def check_condition(product, cond):
field, operator, value = cond
return operators[operator](product[field], value)
def check_conditions(product, conditions, combinator=all):
return combinator(
check_condition(product, cond)
for cond in conditions
)
def check_products_conditions(products, conditions, combinator=all):
return [
product
for product in products
if check_conditions(product, conditions, combinator=combinator)
]
inexpensive = (4, "<=", 1000)
large_screen = (2, ">=", 6.3)
apple_product = (1, "==", "Apple")
product = ['Nova 5T', 'Huawei', 6.26, 3750, 497]
# Check single condition
check_condition(
product,
inexpensive,
)
# Check multiple conditions
check_conditions(
product,
conditions=(
inexpensive,
large_screen,
apple_product,
),
)
# Check multiple products against multiple conditions
matching_products = check_products_conditions(
products=[product, product, product],
conditions=(
inexpensive,
large_screen,
apple_product,
),
)

Python dict using logic input for truth tables

Alright boys and girls here we go. To start off I have a couple of questions. Since my program is large I will simply ask questions in stages, this question being the first. I'm creating a program that generates a truth table for postfix logical expressions. Here are the operators allowed and their logical equivalents:
Operators:
= Logical Equivalence (≡ or ↔)
`->` or `<=` Logical Implication (→)
+ Disjunction (∨), AKA “or”
* Conjunction (∧), AKA “and”
`~` or `!` Negation (¬), AKA “not”
Here are some examples of input and output:
input
p True =
output
p p True =
False False
True True
input
p !
output
p p !
False True
True False
input
p q =
output
p q p q =
False False True
False True False
True False False
True True True
Ok I don't really know where to begin, but I'm not asking for anybody to write this program for me. I know I need to write code using a Python dict, that matches the keys to the corresponding proposition. But how do I know which ones to put for keys and which ones to put for values? Also, in the case of:
`->` or `<=` Logical Implication (→)
and
`~` or `!` Negation (¬), AKA “not”
How do I assign 2 different inputs to be able to be used in a python dict? I hope this isn't too confusing, I'm very noob at python, any help is appreciated. Thank you!
UPDATE
Ok here is the code I have now:
propositions = {
'=' : (2, {(True, True): True,
(True, False): False,
(False, True) : False,
(False, False): True,
}),
'->' : (2, {(True, True): True,
(True, False): False,
(False, True): True,
(False, False): True,
}),
'+' : (2, {(True, True): True,
(True, False): True,
(False, True): True,
(False, False): False,
}),
'*' : (2, {(True, True): True,
(True, False): False,
(False, True): False,
(False, False): False,
}),
'!' : (1, {True: False,
False: True})}
prop = sys.stdin.readline()
prop = prop.split()
prop = prop[::-1]
for x in prop:
I believe I successfully reversed the string and removed all whitespaces, but I am still a bit confused on iterating through it.
SECOND UPDATE here is my code:
propositions = {
'=' : (2, {(True, True): True,
(True, False): False,
(False, True) : False,
(False, False): True,
}),
'->' : (2, {(True, True): True,
(True, False): False,
(False, True): True,
(False, False): True,
}),
'+' : (2, {(True, True): True,
(True, False): True,
(False, True): True,
(False, False): False,
}),
'*' : (2, {(True, True): True,
(True, False): False,
(False, True): False,
(False, False): False,
}),
'!' : (1, {True: False,
False: True})}
prop = sys.stdin.readline()
prop = prop.strip().split()
prop = reversed(prop)
def evaluate():
token = next(prop)
try:
nargs, table = propositions[token]
except KeyError:
if token.lower() in ('true', '1'):
return True
elif token.lower() in ('false', '0'):
return False
else:
return token
return table[tuple(evaluate() for i in range(nargs))]
You have to build your dicts in the order of resolution from outer to inner:
master_dict = {
'=': (2, {(True, True): True,
(True, False): False,
...
}),
...
'!': (1, {True: False,
False: True})}
The numbers indicate how many operands the operator takes.
To parse an input read it from right to left.
Use a recursive function, that consumes one token from the right.
(1) If the token is an operator (i.e. a key in your dictionary) retrieve the corresponding value from your master dict.
The number stored first is the number of arguments the operator takes. So your function must now call itself as many times as there are arguments. Be sure to keep track of which tokens have already be read. One neat way of doing this is using a list iterator, which will spit out each element exactly once, so you can't get the indexing wrong. Once you have all the arguments you apply the truth table you've just retrieved, read out the result and return it.
(2) If the token is not an oprator your function must just return it.
prop = sys.stdin.readline()
def solve_no_var(prop):
rev_iter = reversed(prop)
def evaluate():
token = next(rev_iter)
try:
nargs, table = propositions[token]
except KeyError:
if token.lower() in ('true', '1'):
return True
elif token.lower() in ('false', '0'):
return False
else:
return token
return table[tuple(evaluate() for i in range(nargs))]
return evaluate()
def solve(prop):
prop = prop.strip().split()
variables = list(set(prop) - set(propositions)
- {'True', 'TRUE', 'true', '1', 'False', 'FALSE', 'false', '0'})
lookup = {v: [j for j, p in enumerate(prop) if p == v] for v in variables}
N = len(variables)
print((N*" {:6} ").format(*variables), 'result')
for p in itertools.product(("True", "False"), repeat=N):
prop_nv = prop.copy()
for v, b in zip (variables, p):
for j in lookup[v]:
prop_nv[j] = b
res = solve_no_var(prop_nv)
print(((N+1)*" {:6} ").format(*(p + (res,))))
solve(prop)

Modifying nested dictionaries

Given this two dicts:
empty = {'151': {'1': 'empty', '0': 'empty', '2': '2.30'}}
full = {'151': {'1': 3.4, '0': 3.6, '2': 2}}
Firstly, I want to check if empty.keys() == full.keys() if it holds, I want to replace the empty values with corresponding value from full dictionary. It ought to result in:
not_empty = {'151': {'1': '3.4', '0': '3.6', '2': '2.30'}}
My solution so far: I thought I would identify all the keys with empty values using regex, but for whatever reason my code so far, produces an empty dict {}.
import re
find_empty = re.findall("'(\d)':\s'empty'", str(empty))[0]
if empty.keys() == full.keys():
k = empty.values()[0].keys()
v = empty.values()[0].values()
print {k:v for k,v in empty.values()[0].iteritems()\
if empty.values()[0][find_empty] != 'empty'}
I hoped it can output {'151': {'2': '2.30'}} for a good starting point. Anyway, I guess there exists more clean solution then regex for this task so any hints are welcomed!
Regex is not the right tool for this job. I would suggest a recursive approach like the following.
empty = {'151': {'1': 'empty', '0': 'empty', '2': '2.30'}}
full = {'151': {'1': 3.4, '0': 3.6, '2': 2}}
def repl(a, b):
clean = {}
for k, v in a.items():
# This is the case where we want to replace what we have in b if we have something. Just in case, use the dict.get method and provide a default.
if v == 'empty':
clean[k] = b.get(k, 'Not there')
# If the value is another dict, then call this function with the value, and put the return as the value for our current key
elif isinstance(v, dict):
v_clean = repl(v, b.get(k, {}))
clean[k] = v_clean
# The value isn't equal to 'empty', and it isn't another dict, so just keep the current value.
else:
clean[k] = v
# Finally, return the cleaned up dictionary.
return clean
print repl(empty, full)
OUTPUT
{'151': {'1': 3.4, '0': 3.6, '2': '2.30'}}
EDIT I am not sure if this takes care of all of your cases, but it probably worth a look anyway.
empty = {'151': {'1': 'empty', '0': 'empty', '2': '2.30', '8': ['empty', 'empty', 5, {"foo2": "bar2", "1": "empty"}]}}
full = {'151': {'1': 3.4, '0': 3.6, '2': 2, '8': ['foo', 'bar', 'baz', {"foo3": "bar3", "1": "2"}]}}
def repl(a, b):
if isinstance(a, dict) and isinstance(b, dict):
clean = {}
for k, v in a.items():
# This is the case where we want to replace what we have in b if we have something. Just in case, use the dict.get method and provide a default.
if v == 'empty':
clean[k] = b.get(k, 'Not there')
# If the value is another dict, then call this function with the value, and put the return as the value for our current key
elif isinstance(v, dict):
v_clean = repl(v, b.get(k, {}))
clean[k] = v_clean
# The value isn't equal to 'empty', and it isn't another dict, so just keep the current value.
elif isinstance(v, list):
v_clean = repl(v, b.get(k, []))
clean[k] = v_clean
else:
clean[k] = v
# Finally, return the cleaned up dictionary.
elif isinstance(a, list) and isinstance(b, list):
clean = []
for item_a, item_b in zip(a, b):
if item_a == 'empty':
clean.append(item_b)
elif isinstance(item_a, dict):
clean_a = repl(item_a, item_b)
clean.append(clean_a)
else:
clean.append(item_a)
return clean
print repl(empty, full)
OUTPUT
{'151': {'1': 3.4, '0': 3.6, '2': '2.30', '8': ['foo', 'bar', 5, {'1': '2', 'foo2': 'bar2'}]}}

Compare dictionaries ignoring specific keys

How can I test if two dictionaries are equal while taking some keys out of consideration. For example,
equal_dicts(
{'foo':1, 'bar':2, 'x':55, 'y': 77 },
{'foo':1, 'bar':2, 'x':66, 'z': 88 },
ignore_keys=('x', 'y', 'z')
)
should return True.
UPD: I'm looking for an efficient, fast solution.
UPD2. I ended up with this code, which appears to be the fastest:
def equal_dicts_1(a, b, ignore_keys):
ka = set(a).difference(ignore_keys)
kb = set(b).difference(ignore_keys)
return ka == kb and all(a[k] == b[k] for k in ka)
Timings: https://gist.github.com/2651872
def equal_dicts(d1, d2, ignore_keys):
d1_filtered = {k:v for k,v in d1.items() if k not in ignore_keys}
d2_filtered = {k:v for k,v in d2.items() if k not in ignore_keys}
return d1_filtered == d2_filtered
EDIT: This might be faster and more memory-efficient:
def equal_dicts(d1, d2, ignore_keys):
ignored = set(ignore_keys)
for k1, v1 in d1.iteritems():
if k1 not in ignored and (k1 not in d2 or d2[k1] != v1):
return False
for k2, v2 in d2.iteritems():
if k2 not in ignored and k2 not in d1:
return False
return True
Using dict comprehensions:
>>> {k: v for k,v in d1.items() if k not in ignore_keys} == \
... {k: v for k,v in d2.items() if k not in ignore_keys}
Use .viewitems() instead on Python 2.
Here's another variant:
set(ignore_keys).issuperset(k for (k, v) in d1.items() ^ d2.items())
Its virtues:
C speed identification of differences between the dicts
C speed check for membership in the set of ignored keys
Early-out if a single mismatch is found
Very very crudely, you could just delete any ignored keys and compare those dictionaries:
def equal_dicts(d1, d2, ignore_keys=()):
d1_, d2_ = d1.copy(), d2.copy()
for k in ignore_keys:
try:
del d1_[k]
except KeyError:
pass
try:
del d2_[k]
except KeyError:
pass
return d1_ == d2_
(Note that we don't need a deep copy here, we just need to avoid modifying d1 and d2.)
def compare_dict(d1, d2, ignore):
for k in d1:
if k in ignore:
continue
try:
if d1[k] != d2[k]:
return False
except KeyError:
return False
return True
Comment edit: You can do something like compare_dict(d1, d2, ignore) and compare_dict(d2, d1, ignore) or duplicate the for
def compare_dict(d1, d2, ignore):
ignore = set(ignore)
for k in d1:
if k in ignore:
continue
try:
if d1[k] != d2[k]:
return False
except KeyError:
return False
for k in d2:
if k in ignore:
continue
try:
if d1[k] != d2[k]:
return False
except KeyError:
return False
return True
Whatever is faster and cleaner!
Update: cast set(ignore)
If you need this check when testing, you can use the ANY from the unittest.mock library.
Here is an example.
from unittest.mock import ANY
actual = {'userName':'bob', 'lastModified':'2012-01-01'}
expected = {'userName':'bob', 'lastModified': ANY}
assert actual == expected
See more
Optimal solution for the case of ignoring only one key
return all(
(x == y or (x[1] == y[1] == 'key to ignore')) for x, y in itertools.izip(
d1.iteritems(), d2.iteritems()))
in case your dictionary contained lists or other dictionaries:
def equal_dicts(d1, d2, ignore_keys, equal):
# print('got d1', d1)
# print('got d2', d2)
if isinstance(d1, str):
if not isinstance(d2, str):
return False
return d1 == d2
for k in d1:
if k in ignore_keys:
continue
if not isinstance(d1[k], dict) and not isinstance(d1[k], list) and d2.get(k) != d1[k]:
print(k)
equal = False
elif isinstance(d1[k], list):
if not isinstance(d2.get(k), list):
equal = False
if len(d1[k]) != len(d2[k]):
return False
if len(d1[k]) > 0 and isinstance(d1[k][0], dict):
if not isinstance(d2[k][0], dict):
return False
d1_sorted = sorted(d1[k], key=lambda item: item.get('created'))
d2_sorted = sorted(d2[k], key=lambda item: item.get('created'))
equal = all(equal_dicts(x, y, ignore_keys, equal) for x, y in zip(d1_sorted, d2_sorted)) and equal
else:
equal = all(equal_dicts(x, y, ignore_keys, equal) for x, y in zip(d1[k], d2[k])) and equal
elif isinstance(d1[k], dict):
if not isinstance(d2.get(k), dict):
equal = False
print(k)
equal = equal_dicts(d1[k], d2[k], ignore_keys, equal) and equal
return equal

Categories

Resources