Как фильтровать файл на основе datetime?

#python #list #file #datetime

#python #Список #файл #дата и время

Вопрос:

У меня есть файл, и я хочу добавить несколько строк в пустой список, если они соответствуют 2 условиям:

  1. Я беру только те строки, в которых есть a country_code , который также присутствует в my_countrycodes И
  2. для каждого country_code я беру МАКСИМАЛЬНУЮ дату-время, если эта дата-время < my_time1

Пожалуйста, обратите внимание, что country_code каждая строка индексируется [1] в файле, а дата-время каждой строки является переменной с именем date_time4 .

Это мой код:

 my_time = '2020-09-06 16:00:45'
my_time1 =  datetime.datetime.strptime(my_time, '%Y-%m-%d %H:%M:%S') 

my_countrycodes = ['555', '256', '1000']

all_row_times = [] #<--- this is the list where we will append the datetime values of the file
new_list = [] #<--- this is the final list where we will append our results
    
with open(root, 'r') as out:
    reader = csv.reader(out, delimiter = 't')
    for row in reader:  
        # print(row)
        date_time1 = row[-2]   row[-1] #<--- concatenate date   time
        date_time2 = datetime.datetime.strptime(date_time1, '%d-%m-%Y%H:%M:%S') #<--- make a datetime object of the string
        date_time3 = datetime.datetime.strftime(date_time2, '%Y-%m-%d %H:%M:%S') #<--- turn the datetime object  back to a string
        date_time4 = datetime.datetime.strptime(date_time3, '%Y-%m-%d %H:%M:%S') #<--- turn the string object  back to a datetime object
        all_row_times.append(date_time4) #<--- put all the datetime objects into a list.
        
        if any(country_code in row[1] for country_code in my_countrycodes) and date_time4 == max(dt for dt in all_row_times if dt <  my_time1): 
            new_list.append(row) #<-- append the rows with the same country_code in my_countrycodes and the latest time if that time is < my_time1
                
print(new_list)
  

Вот как выглядит файл:
введите описание изображения здесь

Это вывод new_list :

 [['USA', '555', 'White', 'True', 'NY', '06-09-2020', '10:11:32'], 
['USA', '555', 'White', 'True', 'BS', '06-09-2020', '10:11:32'], 
['EU', '256', 'Blue', 'False', 'BR', '06-09-2020', '11:26:21'], 
['GE', '1000', 'Green', 'True', 'BE', '06-09-2020', '14:51:45'], 
['GE', '1000', 'Green', 'True', 'BE', '06-09-2020', '15:59:45']]
  

Как вы можете видеть, код извлекает строки с country_codes 555 помощью , 256 и 1000 , он также принимает строки, которые меньше, чем < my_time1 . Итак, эта часть работает идеально. Однако строка 1000 имеет 2 разных даты и времени, и я не понимаю, почему она не принимает только максимальное время даты.

Это ожидаемый результат new_list :

 [['USA', '555', 'White', 'True', 'NY', '06-09-2020', '10:11:32'], 
['USA', '555', 'White', 'True', 'BS', '06-09-2020', '10:11:32'], 
['EU', '256', 'Blue', 'False', 'BR', '06-09-2020', '11:26:21'],  
['GE', '1000', 'Green', 'True', 'BE', '06-09-2020', '15:59:45']]
  

Ответ №1:

На самом деле, требуется только МАКСИМАЛЬНОЕ значение даты и времени, но в цикле for на 14:51:45 первом месте. Ваш код сравнивает это с другими, и, поскольку другое значение еще не появилось, оно принимается за максимальное значение.

На следующей итерации появляется другой код страны, и, поскольку это время больше, чем у других, эта строка также добавляется. Я думаю, это то, чего вам не хватает.

Вы можете попробовать что-то вроде этого.

 my_time =  datetime.datetime.strptime('2020-09-06 16:00:45', '%Y-%m-%d %H:%M:%S')
my_countrycodes = ['555', '256', '1000']

country_code_max_date_rel = {}
matched_rows = []
with open(root, 'r') as out:
    reader = csv.reader(out, delimiter = 't')
    for row in reader:
        date_time = datetime.datetime.strptime(row[-2]   row[-1], '%d-%m-%Y%H:%M:%S')
        if any(country_code in row[1] for country_code in my_countrycodes):
            matched_rows.append(row)
            try:
                if country_code_max_date_rel[str(row[1])] < date_time:
                    raise KeyError
            except KeyError:
                country_code_max_date_rel[str(row[1])] = date_time
  

На данный момент у вас есть максимальное значение для каждой страны. А также список строк.
Если вы снова фильтруете, как;

 new_list = []
for row in matched_rows:
    country_code = row[1]
    date_time = datetime.datetime.strptime(row[-2]   row[-1], '%d-%m-%Y%H:%M:%S')
    if date_time == country_code_max_date_rel[country_code]:
        if date_time < my_time:
            new_list.append(row)
  

Новый список:

 [['USA', '555', 'White', 'True', 'NY', '06-09-2020', '10:11:32'],
 ['USA', '555', 'White', 'True', 'BS', '06-09-2020', '10:11:32'],
 ['EU', '256', 'Blue', 'False', 'BR', '06-09-2020', '11:26:21'],
 ['GE', '1000', 'Green', 'True', 'BE', '06-09-2020', '15:59:45']]
  

Этот код не очень хорош, но я думаю, он поможет вам обновить ваш.

Комментарии:

1. Спасибо, аби. Действительно отличный фрагмент кода. Вы не возражаете, если я расскажу вам в личке, что именно вы сделали?

2. Спасибо, брат, я проверю это.

3. Я не вижу my_time возврата в вашем коде? Что вы с этим сделали? Откуда ваш код знает, что он должен принимать только те строки, которые < then my_time

Ответ №2:

Извините, я не уверен, что вы пытаетесь здесь сделать. Предполагая, что вы хотите иметь только один экземпляр contrycode в вашем new_list с последним временем, прежде my_tim1 чем вот ответ:

Логика в вашем коде неверна. Прямо сейчас вы перебираете все строки из своего csv-файла и применяете то же условие перед добавлением новой строки new_list .
В данном случае ['GE', '1000', 'Green', 'True', 'BE', '06-09-2020', '15:59:45'] добавляется, потому что условие 1 истинно (1000 находится в my_countrycodes), а условие 2 также истинно ( '06-09-2020', '15:59:45' меньше, my_time1 и это также «самое большое» время new_list ).

Вы могли бы решить эту проблему разными способами, но вот несколько предложений:

  1. Измените свое решение следующим образом:
    проверьте, включено ли row[1] str(my_countrycodes) ,
    проверьте, меньше ли время строки my_time1
    Проверьте, указан ли код страны в строке new_list ,
    если его нет, new_list добавьте его,
    если он есть, new_list проверьте, соответствуют ли новые дата и время вашему условию, и если да, обновите столбец даты и времени для этой строки.

  2. Отфильтруйте ваш файл по кодам стран, а затем извлеките максимум из отфильтрованного результата для каждого кода страны

Будьте осторожны, какой у вас ключ, поскольку у вас есть countrycode , который повторяется с разными параметрами. (‘NY’, ‘BS’)

Предложения и комментарии:

  1. Для быстрого доступа к данным вы можете использовать словари. Использование countrycode в качестве ключа предоставит вам легкий доступ к данным и поможет быстро проверить их существование и обновить его параметры.
  2. any(country_code in row[1] for country_code in my_countrycodes)
    может быть записан как:
    row[1] in str(my_countrycodes)
    или вы даже могли бы создать my_country_code_str = str(my_countrycodes) перед вводом цикла for.
  3. Я не знаю, почему вы перебрасываете дату и время назад, но поскольку вам нужен только последний, этого достаточно, чтобы сделать это:
    rows_date_time = datetime.datetime.strptime(row[-2] row[-1], '%d-%m-%Y%H:%M:%S')
    помните, что вы можете отформатировать его по своему усмотрению с помощью '%d-%m-%Y%H:%M:%S'
  4. Не забудьте дать своим переменным осмысленные имена и придерживаться одного стандарта кодирования в вашем коде (ig. когда вы используете подчеркивание, используйте его последовательно)