Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Finding the earliest date in list of custom date objects

Given a list of date objects I need to find the date that comes earliest in a file

I have written the following code to do this:

return min(dates, key=lambda x: x.year)

Each object has a year, month, and day attribute.
I must use a custom class which I have created (at bottom of post)

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

This code works until there are two dates with the same year. If two dates have the same year it returns which one comes first in the list which is not what is expected.

For example, these two dates:

1988 10 10
1988 09 03

The function should return 1988 09 03 but instead it returns 1988 10 10 as it comes first.

How do I compare multiple values of an object in python?

I have also tried this

return min(min(min(dates, key=lambda x: x.year), key=lambda x: x.month), key=lambda x: x.day)

but it doesn’t seem to work

I have also tried

return min(dates)

but this simply returns the last date in the list

sample of dates file:

1954 10 04
1987 12 20
1993 3 10
1996 7 29
1994 5 30
1993 6 9
1989 12 21
2001 6 30
1995 6 14
2002 2 28
1988 6 21
class Date(object):
    def __init__(self, year, month=1, day=1):
        self.year = year
        self.month = month
        self.day = day

    def __str__(self):
        return '{}/{}/{}'.format(self.year, self.month, self.day)

    def __lt__(self, other):
        return (self.year, self.month, self.day) < (other.year, other.month, other.day)

    def __gt__(self, other):
        return (self.year, self.month, self.day) > (other.year, other.month, other.day)

    def __eq__(self, other):
        return (self.year, self.month, self.day) == (other.year, other.month, other.day)

    def __le__(self, other):
        return (self.year, self.month. self.day) <= (other.year, other.month, other.day)

    def __ge__(self, other):
        return (self.year, self.month, self.day) >= (other.year, other.month, other.day)

    def __ne__(self, other):
        return (self.year, self.month, self.day) != (other.year, other.month, other.day)

Parsing:

def parse_dates(content):
    dates = []
    for line in content:
        line_date = line.strip().split()
        dates.append(Date(line_date[0], line_date[1], line_date[2]))

    return dates

The file is simply opened and then passed through this which returns a list of date objects

Then, it is passed into this to return the earliest date:

def find_earliest(dates):
    return min(dates)
The file where the dates are retrieved from is shown above

Solved
I hadn’t casted the dates to an int so they stayed as strings, thus the program was comparing strings not actual number values. I simply casted everything to an int then created the date object.

>Solution :

If you don’t cast to int in your Date constructor, you need to do it in your parsing:

def parse_dates(content):
    dates = []
    for line in content:
        line_date = line.strip().split()
        dates.append(Date(*map(int, line_date)))

    return dates

If you don’t want to define all the dunder comparsion methods, you can use functools.total_ordering:

from functools import total_ordering

@total_ordering
class Date(object):
    def __init__(self, year, month=1, day=1):
        #cast your values to ints
        self.year  = int(year)
        self.month = int(month)
        self.day   = int(day)

        if set(map(int,[self.year,self.month,self.day])) != set(int):
            raise TypeError("Supplied values must be cast-able to `int`")

    def __str__(self):
        # using f-string and padding
        # to get "1994/02/07" instead of "1994/2/7"
        return f'{self.year}/{self.month:02}/{self.day:02}'

    def __eq__(self, other):
        return self.year  == other.year
           and self.month == other.month
           and self.day   == other.day

    def __lt__(self, other):
        # works because or short-circuits on first True
        return self.year  < other.year
            or self.month < other.month
            or self.day   < other.day
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading