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)
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.
CodePudding user response:
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
or as a one-liner:
def parse_dates(content):
return [Date(*map(int, line.strip().split())) for line in content]
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)
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