Problem:
I have a very simple problem where I need to update the one date(either origDate or destDate) to another(either origDate or destDate) if anyone out of two is None, Empty or Non-Exists and if both of them do not exists then set both as None.
I am looking for a pythonic way to achieve this. My current code works fine but it is verbose
Example Input:
1. origin_dest_date = {
"originDate": "2019-06-30 23:59:00.000",
"destDate": None
}
2. origin_dest_date = {
"originDate": "2019-06-30 23:59:00.000"
}
3. origin_dest_date = {
"originDate": ""
}
Output:
1. origin_dest_date = {
"originDate": "2019-06-30 23:59:00.000",
"destDate": "2019-06-30 23:59:00.000"
}
2. origin_dest_date = {
"originDate": "2019-06-30 23:59:00.000",
"destDate": "2019-06-30 23:59:00.000"
}
- origin_dest_date = {
"originDate": None, "destDate": None }
My Code:
from dateutil.parser import parse
origin_dest_date = {
"originDate": "2019-06-30 23:59:00.000",
"destDate": None
}
isoriginDate = False
isdestDate = False
if 'originDate' in origin_dest_date:
isoriginDate = True
if origin_dest_date['originDate'] is not None and \
not origin_dest_date['originDate'] == '':
parse(origin_dest_date['originDate'])
if origin_dest_date['originDate'] == '':
origin_dest_date['originDate'] = None
if 'destDate' in origin_dest_date:
isdestDate = True
if origin_dest_date['destDate'] is not None and \
not origin_dest_date['destDate'] == '':
parse(origin_dest_date['destDate'])
if origin_dest_date['destDate'] == '':
origin_dest_date['destDate'] = None
if isoriginDate and not isdestDate:
origin_dest_date['destDate'] = origin_dest_date['originDate']
elif not isoriginDate and isdestDate:
origin_dest_date['originDate'] = origin_dest_date['destDate']
elif isoriginDate and origin_dest_date['originDate'] is None and \
isdestDate and \
origin_dest_date['destDate'] is not None:
origin_dest_date['originDate'] = origin_dest_date['destDate']
elif isdestDate and \
origin_dest_date['destDate'] is None and \
isoriginDate and \
origin_dest_date['originDate'] is not None:
origin_dest_date['destDate'] = origin_dest_date['originDate']
elif not isoriginDate and not isdestDate:
origin_dest_date['originDate'] = None
origin_dest_date['destDate'] = None
print(origin_dest_date)
7 Answers 7
Two main things to improve in your code:
Use variables to make it look cleaner, especially the conditionals, so you don't repeatedly access the same value in the dictionary;
Use the dictionary
getmethod to lookup a key - it returns its corresponding value if the key exists, ifNoneotherwise. Then simply check if the returned value is truthy in Python, which accounts for bothNoneand empty strings.setdefaultmay also be used when setting the values at the end.
This is an example of how to implement those things in order to simplify your code:
from dateutil.parser import parse
origin_dest_date = { "originDate": "2019-06-30 23:59:00.000", "destDate": None }
origin = origin_dest_date.get("originDate")
dest = origin_dest_date.get("destDate")
if origin and not dest:
origin_dest_date["destDate"] = parse(origin)
elif not origin and dest:
origin_dest_date["originDate"] = parse(dest)
elif not origin and not dest:
if origin_dest_date.setdefault("originDate", None) is not None: # conditional for empty string
origin_dest_date["originDate"] = None
if origin_dest_date.setdefault("destDate", None) is not None: # conditional for empty string
origin_dest_date["destDate"] = None
3 Comments
if origin is not None and not dest to make a narrower condition. Otherwise you cannot distinguish between empty string and None which may or may not be what you want.Here is my attempt:
def fill_dict(origin_dest_date, key1, key2):
if not origin_dest_date.get(key1):
origin_dest_date[key1] = origin_dest_date.get(key2) or None
fill_dict(origin_dest_date, 'destDate', 'originDate')
fill_dict(origin_dest_date, 'originDate', 'destDate')
The key idea is:
- use dict.get(key)
which will return
Noneif the key doesn't exist in the dictionary - use loose
ifstatement. Empty string orNone(which is the case if the key doesn't exist in the dictionary) will resolve toFalse.
4 Comments
get(key1, None) could be shortened to get(key1)KeyError. Thanks @ababakget(key2, None)Try this,
>>> def org_dest(d):
for k,v in d.items():
date_struc[k]=v
if all(date_struc.values()):
pass
else:
for k,v in date_struc.items():
if not v:
date_struc[k]= "".join([val for val in date_struc.values() if val])
return date_struc
Final structure with default values as None which will be updated by the function.
>>> date_struc = {"originDate": None, "destDate": None}
Test:
>>> date_struc = {"originDate": None, "destDate": None}
origin_dest_date_1 = {"originDate": "2019-06-30 23:59:00.000", "destDate": None}
>>> org_dest(origin_dest_date_1) # test-2 output
{'originDate': '2019-06-30 23:59:00.000', 'destDate': '2019-06-30 23:59:00.000'}
>>> origin_dest_date_2 = {"originDate": "2019-06-30 23:59:00.000"}
>>> org_dest(origin_dest_date_2) #test-2 output
{'originDate': '2019-06-30 23:59:00.000', 'destDate': '2019-06-30 23:59:00.000'}
Comments
With a custom function and sample template dict:
def arrange_date_keys(d):
temp = {'originDate': None, 'destDate': None} # sample dict
if not d.get('originDate') or not d.get('destDate'):
date_value = d.get('originDate') or d.get('destDate')
return temp.fromkeys(temp, date_value)
return d
origin_dest_date1 = {
"originDate": "2019-06-30 23:59:00.000", "destDate": None
}
origin_dest_date2 = {
"originDate": "2019-06-30 23:59:00.000"
}
origin_dest_date3 = {
"originDate": ""
}
origin_dest_date4 = {
"originDate": "2019-06-30 23:59:00.000", "destDate": "2019-06-30 23:59:00.000"
}
print(arrange_date_keys(origin_dest_date1))
print(arrange_date_keys(origin_dest_date2))
print(arrange_date_keys(origin_dest_date3))
print(arrange_date_keys(origin_dest_date4))
The consecutive output:
{'originDate': '2019-06-30 23:59:00.000', 'destDate': '2019-06-30 23:59:00.000'}
{'originDate': '2019-06-30 23:59:00.000', 'destDate': '2019-06-30 23:59:00.000'}
{'originDate': None, 'destDate': None}
{'originDate': '2019-06-30 23:59:00.000', 'destDate': '2019-06-30 23:59:00.000'}
2 Comments
If you need this only for two static keys, that you can try this, two line of code
must = {"originDate", "destDate"}
test = {"originDate":"2019-06-30 23:59:00.000", "destDate": None}
test.update({key:test[list(test.keys()-key)[0]] for key in must if key not in test or test[key] is None})
Tried with one None value :
test = {"originDate":"2019-06-30 23:59:00.000", "destDate": None}
test.update({key:test[list(test.keys()-key)[0]] for key in must if key not in test or test[key] is None})
test
{'originDate': '2019-06-30 23:59:00.000', 'destDate': '2019-06-30 23:59:00.000'}
Tried with one key:
test = {"originDate":"2019-06-30 23:59:00.000",}
test.update({key:test[list(test.keys()-key)[0]] for key in must if key not in test or test[key] is None})
test
{'originDate': '2019-06-30 23:59:00.000', 'destDate': '2019-06-30 23:59:00.000'}
Comments
Update:
try:
if 'destDate' not in origin_dest_date:
origin_dest_date['destDate'] = origin_dest_date['originDate']
elif not origin_dest_date['destDate']:
origin_dest_date['destDate'] = origin_dest_date['originDate']
except KeyError as e:
pass
print(origin_dest_date)
Comments
This is the most accurate solution given by @deceze
origin_dest_date = {
"originDate": "2019-06-30 23:59:00.000",
"destDate": "2019-06-30 23:58:00.000"
}
if not origin_dest_date.get('originDate') or not origin_dest_date.get('destDate'):
d = (origin_dest_date.get('originDate') or None) or (origin_dest_date.get('destDate') or None)
origin_dest_date = {'originDate': d, 'destDate': d}
print(origin_dest_date)
1 Comment
d = origin_dest_date.get('originDate') or origin_dest_date.get('destDate') or None is sufficient. Also, the duplicate .get calls can be avoided.
d = odd.get('originDate') or odd.get('destDate'); odd = {'originDate': d, 'destDate': d}...?