Home > database >  Push None or empty values to last of json array in datetime sorted lambda function
Push None or empty values to last of json array in datetime sorted lambda function

Time:10-03

I am building a simple function But I am stuck on an error, I am trying to sort json array based on datetime defined it the response. But JSON array also contains some None and Empty string dates like "". so It is showing

KeyError: 'date' when it sees None or empty date value

so I am trying to push these type of value in the last of the sorted json array which have None and empty string values (date).

example_response = [
    {
      "id": 2959,
      "original_language": "Permanent Job",
      "date": "2012-10-26",
      "absent": False
    },
    {
      "id": 8752,
      "original_language": "Intern Job",
      "date": "",
      "absent": True
    },
    {
      "adult": False,
      "id": 1300,
      "title": "Training Job",
      "date": "2020-07-25",
      "absent": False
    },
    {
      "adult": False,
      "id": 7807,
      "title": "Training Job",
      "absent": False
    },
]

program.py

def sorting_function(response):
    if response == True:
        sorted_data = sorted(example_response, key=lambda x: datetime.strptime(x['date'], "%Y-%m-%d"))
        print(sorted_data)

    return sorted_data

As you can see in example_response one dict has empty string and one don't have "date". When I run this function then it is showing KeyError: 'date'

What I have tried ?

I have also tried using

sorted_data = sorted(example_response, key=lambda x: (x['date'] is None, x['date'] == "", x['date'], datetime.strptime(x['date']), "%Y-%m-%d"))

But it still showing KeyError.

Any help would be much Appreciated.

CodePudding user response:

Dictionaries have a very useful get() function which you could utilise thus:

example_response = [
    {
      "id": 2959,
      "original_language": "Permanent Job",
      "date": "2012-10-26",
      "absent": False
    },
    {
      "id": 8752,
      "original_language": "Intern Job",
      "date": "",
      "absent": True
    },
    {
      "adult": False,
      "id": 1300,
      "title": "Training Job",
      "date": "2020-07-25",
      "absent": False
    },
    {
      "adult": False,
      "id": 7807,
      "title": "Training Job",
      "absent": False
    }
]

example_response.sort(key=lambda d: d.get('date', ''))

print(example_response)

In this case, missing or empty 'date' values would precede any other dates.

Output:

[{'id': 8752, 'original_language': 'Intern Job', 'date': '', 'absent': True}, {'adult': False, 'id': 7807, 'title': 'Training Job', 'absent': False}, {'id': 2959, 'original_language': 'Permanent Job', 'date': '2012-10-26', 'absent': False}, {'adult': False, 'id': 1300, 'title': 'Training Job', 'date': '2020-07-25', 'absent': False}]

CodePudding user response:

Don't call strptime if x['date'] is None

If the key is

lambda x: (x['date'] is None, datetime.strptime(x['date'], "%Y-%m-%d"))

Then the pair will be computed for all values, which means strptime will be called on all x['date'], including those that are None.

I suggest using a conditional, in order to only call strptime if x['date'] is not None:

lambda x: (0, datetime.strptime(x['date'], "%Y-%m-%d")) if x['date'] is not None else (1, 0)

Use x.get('date') instead of x['date'] if x might be missing the 'date' key

If x is a dict that doesn't have a 'date', then attempting to access x['date'] will always cause a KeyError, even for something as simple as x['date'] is None.

Instead, you can use dict.get, which doesn't cause errors. If a value is missing, dict.get will return None, or another value which you can provide as a second argument:

x = { "id": 2959, "original_language": "Permanent Job" }

print(x['date'])
# KeyError

print(x.get('date'))
# None

print(x.get('date', 42))
# 42

Finally, the key function for the sort becomes:

lambda x: (0, datetime.strptime(x.get('date'), "%Y-%m-%d")) if x.get('date') is not None else (1, 0)

Note that if the key function becomes too complex, it might be better to write it using def instead of lambda:

def key(x):
    date = x.get('date')
    if date is None:
        return (1, 0)
    else:
        return (0, datetime.strptime(date, "%Y-%m-%d"))
  • Related