Get minimum of SortedKeyList with a condition on an object attribute

Question:

I have a SortedKeyList of objects sorted by timestamp, the objects also have another attribute, the ID.

I was trying to get the earliest element of the list based on the ID.

This is a code example:

import numpy as np
import sortedcontainers

class Point:
    def __init__(self, timestamp, id):
        self.timestamp = timestamp
        self.id = id

point_list = sortedcontainers.SortedKeyList(key=lambda x: x.timestamp)

point_list.add(Point(np.datetime64("2021-07-05T09:00:00"), "B"))
point_list.add(Point(np.datetime64("2021-07-05T09:00:01"), "A"))
point_list.add(Point(np.datetime64("2021-07-05T09:00:03"), "A"))
point_list.add(Point(np.datetime64("2021-07-05T09:01:00"), "B"))

I would like to select on the ID and take the minimum.

For example I want the earliest point for ID=A and, in this case, is:

Point(np.datetime64("2021-07-05T09:00:01"), "A")

I was trying to do something like this:

min(point_list, key=lambda x: x.timestamp if(x.id=="A") else None).timestamp

but this give me a TypeError:

TypeError: '<' not supported between instances of 'datetime.datetime' and 'NoneType'

This is part of a bigger project, so I can refactor the part related to SortedKeyList, but I can’t modify the object Point.

Any idea?

Asked By: cicciodevoto

||

Answers:

Following @hpaulj I used a late np.datetime64:

min(point_list, key=lambda x: x.timestamp if(x.id=="A") else np.datetime64("now").astype("datetime64[ns]")).timestamp

as the time precision over the other timestamp is in nanoseconds, I am pretty confident that this should be fine.

Answered By: cicciodevoto

As the list is already sorted by timestamp, you need to iterate only until you see an item with the given id. This should be faster for the average case than using min():

point_id = 'A'
min_point = None

for point in point_list:
    if point.id == point_id:
        min_point = point
        break

Or as a one-liner:

min_point = next((point for point in point_list if point.id == point_id), None)
Answered By: Eugene Yarmash