1

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"
                            }
  1. 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)
9
  • 1
    d = odd.get('originDate') or odd.get('destDate'); odd = {'originDate': d, 'destDate': d}…? Commented Sep 5, 2019 at 10:22
  • 2
    @deceze But then if both keys exist you'll end up overwriting one. Commented Sep 5, 2019 at 10:24
  • @deceze what is this called in Python? Commented Sep 5, 2019 at 10:26
  • @Aran I think the spec is unclear on what's supposed to happen in that case… Commented Sep 5, 2019 at 10:26
  • @deceze if both available then it should return as it is without over-writing Commented Sep 5, 2019 at 10:26

7 Answers 7

1

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 get method to lookup a key - it returns its corresponding value if the key exists, if None otherwise. Then simply check if the returned value is truthy in Python, which accounts for both None and empty strings. setdefault may 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
Sign up to request clarification or add additional context in comments.

3 Comments

Use 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.
Don't you need to either parse both values or leave both of them as text?
@GiacomoAlzetta OP said to perform the same operation if the values are None or "empty", which I interpreted as being an empty string.
1

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:

  1. use dict.get(key) which will return None if the key doesn't exist in the dictionary
  2. use loose if statement. Empty string or None (which is the case if the key doesn't exist in the dictionary) will resolve to False.

4 Comments

get(key1, None) could be shortened to get(key1)
I assumed it will raise KeyError. Thanks @ababak
There's one more: get(key2, None)
there were only two use cases when I started writing this code. I made minor change to incorporate the third use case as well.
1

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

1

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

It fails when both the dates are available
@min2bro, that's really simple to fix - see my update
0

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

0

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

0

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.