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

How can I find all datetimes in a list within n minutes of a given value?

I have two lists of times (Hour:Min:Sec format) and I’ve been struggling to compare each entry in list_a against all of list_b to identify values that fall within 30 minutes:

list_a = ["10:26:42", "8:55:43", "7:34:11"]
list_b = ["10:49:20", "8:51:10", "10:34:35", "8:39:47", "7:11:49", "7:42:10"]

Expected Output:

10:26:42 is within 30m of 10:49:20, 10:34:35
8:55:43 is within 30m of 8:51:10, 8:39:47
7:34:11 is within 30m of 7:11:49, 7:42:10

So far what I’ve been doing is:

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

import datetime

# Convert the Lists to Datetime Format

for data in list_a:
    convert = datetime.datetime.strptime(data,"%H:%M:%S")
    list_a_times.append(convert)

for data in list_b:
    convert = datetime.datetime.strptime(data,"%H:%M:%S")
    list_b_times.append(convert)

# Using a Value of List A, Find the Closest Value in List B

for data in list_a_times:
     closest_to_data = min(list_b_times, key=lambda d: abs(d - data))

     print(data, closest_to_data)

This kind of works, but it only finds one nearest value! How can I manipulate the min() function to keep providing values as long as they’re within the desired 30 minutes or less?

>Solution :

IIUC, you want to compare all combinations, so you need to check all.

Please read the end of the answer for a note on datetime/timedelta.

Using itertools.product:

list_a = ['10:26:42', '8:55:43', '7:34:11']
list_b = ['10:49:20', '8:51:10', '10:34:35', '8:39:47', '7:11:49', '7:42:10']

import datetime
from itertools import product

str2time = lambda s: datetime.datetime.strptime(s, "%H:%M:%S")

for a,b in product(map(str2time, list_a), map(str2time, list_b)):
    if abs(a-b).total_seconds() <= 1800:
        print(f'{a:%H:%M:%S} is within 30m of {b:%H:%M:%S}')

output:

10:26:42 is within 30m of 10:49:20
10:26:42 is within 30m of 10:34:35
08:55:43 is within 30m of 08:51:10
08:55:43 is within 30m of 08:39:47
07:34:11 is within 30m of 07:11:49
07:34:11 is within 30m of 07:42:10

Using nested for loops:

import datetime

str2time = lambda s: datetime.datetime.strptime(s, "%H:%M:%S")

for a in map(str2time, list_a):
    start = f'{a:%H:%M:%S} is within 30m of'
    for b in map(str2time, list_b):
        if abs(a-b).total_seconds() <= 1800:
            print(f'{start} {b:%H:%M:%S}', end='')
            start = ','
    if start == ',':
        print()

output:

10:26:42 is within 30m of 10:49:20, 10:34:35
08:55:43 is within 30m of 08:51:10, 08:39:47
07:34:11 is within 30m of 07:11:49, 07:42:10

note on datetime

Using datetime without date will default to 1970-01-01, which can have edge effects close to midnight. Instead, you could use timedelta objects. With my code you need to change the str2time function to:

def str2time(s):
    h,m,s = map(int, s.split(':'))
    return datetime.timedelta(hours=h, minutes=m, seconds

And alter a bit the code to be able to convert to string:

z = datetime.datetime(1970,1,1)

for a in map(str2time, list_a):
    start = f'{z+a:%H:%M:%S} is within 30m of'
    for b in map(str2time, list_b):
        if abs(a-b).total_seconds() <= 1800:
            print(f'{start} {z+b:%H:%M:%S}', end='')
            start = ','
    if start == ',':
        print()
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