#python #dictionary #iteration
#python #словарь #итерация
Вопрос:
У меня есть словарь строки временных диапазонов, например:
{'10:00-12:00': 'Maths',
'13:00-15:00': 'Physics',
'16:00-18:00': 'History',
'19:00-22:00': 'Biology',
'23:00-01:00': 'Chemistry',
'02:00-04:00': 'Computer',
'05:00-10:00': 'English'}
Теперь я хочу извлечь время окончания, например 12:00
, и 13:00
из словаря и создать словарь с именем второго субъекта.
Итак, результат, который я хочу, это:
{'12:00-13:00':'Physics',
'15:00-16:00':'History',
'18:00-19:00':'Biology',
'22:00-23:00':'Chemistry',
'01:00-02:00':'Computer',
'04:00-05:00':'English'}
Я мог бы просто создать этот словарь сам (путем жесткой настройки значений), но я хотел, чтобы он был динамическим, потому что ключи — это имя столбца фрейма данных (из csv), а значения — это имя поля. Поэтому я хотел, чтобы python динамически подбирал его на основе csv. Я пробовал использовать zip(lst,lst[1:])
, но он не работает со словарем, поскольку индексация отличается для словаря.
Я также пытался использовать:
data = {'10:00-12:00': 'Maths',
'13:00-15:00': 'Physics',
'16:00-18:00': 'History',
'19:00-22:00': 'Biology',
'23:00-01:00': 'Chemistry',
'02:00-04:00': 'Computer',
'05:00-10:00': 'English'}
def pairwise(iterable):
it = iter(iterable)
a = next(it, None)
for b in it:
yield (a, b)
a = b
a = pairwise(data)
print(list(a)) #[('10:00-12:00', '13:00-15:00'), ('13:00-15:00', '16:00-18:00'), ('16:00-18:00', '19:00-22:00'), ('19:00-22:00', '23:00-01:00'), ('23:00-01:00', '02:00-04:00'), ('02:00-04:00', '05:00-10:00')]
#not the keys of the desired output
Спасибо!
Комментарии:
1. Вам лучше сначала проанализировать диапазоны времени даты в надлежащий тип данных, например
datetime
, а затем выполнить манипуляции. Игра с временными строками приведет только к бесчисленным головным болям.2. @rdas На самом деле позже я перебираю dict, делая их datetime.
3. @PatrickArtner Я отредактировал его, теперь стало лучше?
4. Просто для ясности: ваша цель — рассчитать паузу перед сеансом (математика … -12:00, а физика 13:00-… => 12:00-13:00) или просто, чтобы получить час до сеанса (физика — это 13:00-… => 12:00-13:00)? Поскольку все паузы для этих данных длятся один час, оба подхода дают одинаковые результаты.
5. @MisterMiyagi На самом деле да, разница во времени между математикой и физикой равна 1, но она также может увеличиваться или уменьшаться, то есть я пытаюсь проверить, находится ли текущее время между этими 12:00 и 13:00, поэтому для этого я хотел извлечь 12:00 и 13:00. 12:00и 13:00 также может быть что-то вроде 12:00 и 13:30.
Ответ №1:
import more_itertools
from collections import namedtuple
data = {'10:00-12:00': 'Maths', '13:00-15:00': 'Physics',
'16:00-18:00': 'History', '19:00-22:00': 'Biology',
'23:00-01:00': 'Chemistry', '02:00-04:00': 'Computer',
'05:00-10:00': 'English'}
Item = namedtuple('Item', ('start', 'end', 'subject'))
def parse(item):
times, subject = item
start, end = times.split('-')
return Item(start, end, subject)
def generate_items(data):
for item1, item2 in more_itertools.windowed(data,2):
yield f'{item1.end}-{item2.start}', item2.subject
data = [parse(item) for item in data.items()]
print(dict(generate_items(data)))
вывод
{'12:00-13:00': 'Physics', '15:00-16:00': 'History', '18:00-19:00': 'Biology', '22:00-23:00': 'Chemistry', '01:00-02:00': 'Computer', '04:00-05:00': 'English'}
подробнее-пакет iterools удобен, но more_itertools.windowed()
его можно заменить чем-то вроде zip(data[:-1], data[1:])
from collections import namedtuple
data = {'10:00-12:00': 'Maths', '13:00-15:00': 'Physics',
'16:00-18:00': 'History', '19:00-22:00': 'Biology',
'23:00-01:00': 'Chemistry', '02:00-04:00': 'Computer',
'05:00-10:00': 'English'}
Item = namedtuple('Item', ('start', 'end', 'subject'))
def parse(item):
times, subject = item
start, end = times.split('-')
return Item(start, end, subject)
def generate_items(data):
for item1, item2 in zip(data[:-1], data[1:]):
yield f'{item1.end}-{item2.start}', item2.subject
data = [parse(item) for item in data.items()]
print(dict(generate_items(data)))
Комментарии:
1.
more_itertools
? аккуратно.2. Это решение также является динамическим, понятия не имею, что происходит, но это работает здесь. Спасибо!
Ответ №2:
Это даст вам то, что вы хотите
a = {'10:00-12:00': 'Maths', '13:00-15:00': 'Physics', '16:00-18:00': 'History', '19:00-22:00': 'Biology', '23:00-01:00': 'Chemistry', '02:00-04:00': 'Computer', '05:00-10:00': 'English'}
keys_split = list(map(lambda s: s.split("-"), a.keys()))
flatten = lambda l: [item for sublist in l for item in sublist]
ks = flatten(keys_split)
keys_tmp= list(zip(ks[1::2],ks[2::2]))
keys_res = list(map(lambda e: e[0] '-' e[1], keys_tmp))
values_res = list(a.values())[1:]
dict_res = dict(zip(keys_res, values_res))
и при печати будет выглядеть так
print(dict_res)
#{'12:00-13:00': 'Physics', '15:00-16:00': 'History', '18:00-19:00': 'Biology', '22:00-23:00': 'Chemistry', '01:00-02:00': 'Computer', '04:00-05:00': 'English'}
объяснение того, что происходит:
- строка 1: a.keys() предоставит вам все ключи, каждый ключ представляет собой строку
- строка 1: map принимает лямбда-функцию, которая перебирает все строки, которые мы видели в a.keys(), и разделяет их на ‘-‘
print(a.keys())
# dict_keys(['10:00-12:00', '13:00-15:00', '16:00-18:00', '19:00-22:00', '23:00-01:00', '02:00-04:00', '05:00-10:00'])
print(keys_split)
# [['10:00', '12:00'], ['13:00', '15:00'], ['16:00', '18:00'], ['19:00', '22:00'], ['23:00', '01:00'], ['02:00', '04:00'], ['05:00', '10:00']]
- строка 2: flatten — это лямбда-функция, которая выполняет итерацию по списку l и выравнивает список списков до простого списка
- строка 3: примените flatten к keys_split, чтобы получить плоский список
print(ks)
# ['10:00', '12:00', '13:00', '15:00', '16:00', '18:00', '19:00', '22:00', '23:00', '01:00', '02:00', '04:00', '05:00', '10:00']
- строка 4: создайте временный список с помощью zip поверх списка 1 (ks [1::2]) с новыми метками времени начала 12:00, 15:00, 16:00 и т.д. и над списком 2 (k2[2:: 2]) с новыми конечными временными метками 13:00,16:00, 19:00 и т.д.
- строка 5: чтобы получить ключи в нужном формате, сопоставьте все элементы временного списка, чтобы объединить элементы с ‘-‘ между ними, например ’12:00-13:00′, ’15:00-16:00’ и т.д.
print(keys_tmp)
#[('12:00', '13:00'), ('15:00', '16:00'), ('18:00', '19:00'), ('22:00', '23:00'), ('01:00', '02:00'), ('04:00', '05:00')]
print(keys_res)
#['12:00-13:00', '15:00-16:00', '18:00-19:00', '22:00-23:00', '01:00-02:00', '04:00-05:00']
- строка 6: получить все значения из dict a, но не учитывать первый элемент
- строка 7: окончательный dict_res — это zip-файл над двумя списками keys_res и values_res
print(values_res)
#['Physics', 'History', 'Biology', 'Chemistry', 'Computer', 'English']
Надеюсь, это немного прояснит ситуацию, просто перейдите построчно и распечатайте, чтобы посмотреть, что происходит 🙂
Комментарии:
1. У вас там опечатка в строке 5,
keys_split
2. Спасибо! Это тоже работает динамически, хотя я понятия не имею, что происходит, возможно, включите немного информации о том, что здесь происходит.
3. да, конечно, теперь будет добавлена информация, также, если вы распечатаете переменные, это также поможет в том, что происходит
4. Я думаю, что создание функции из этого и передача словаря в качестве аргумента лучше, верно?
5. Да, если вам нужно снова применить эту логику к другим dicts, имеет смысл определить ее как функцию
Ответ №3:
Вероятно, это проще сделать, используя время преобразования datetime.time, но вы можете сделать это на основе чистой строки без какого-либо импорта :
s = {'10:00-12:00': 'Maths', '13:00-15:00': 'Physics',
'16:00-18:00': 'History', '19:00-22:00': 'Biology',
'23:00-01:00': 'Chemistry', '02:00-04:00': 'Computer',
'05:00-10:00': 'English'}
# this is very explicit - you can reduce the amount of variables used
# by making the comprehensions bigger - but for SO I prefer readability
# extract end times and convert to int
times = [ tuple(map(int, (t.split("-")[1]).split(":"))) for t in s.keys()][:-1]
# get lectures
what = list(s.values())[1:]
print(times, what, sep="n")
# create new schedule with end times
new_sched= [f"{v1:02d}:{v2:02d}-{v1 1:02d}:{v2:02d}" for (v1,v2) in times]
# construct new scheduling
m = {}
for when,wh in zip(new_sched,what):
m[when] = wh
# check
print(m)
print( {'12:00-13:00':'Physics', '15:00-16:00':'History',
'18:00-19:00':'Biology', '22:00-23:00':'Chemistry',
'01:00-02:00':'Computer', '04:00-05:00':'English'})
Вывод:
# parsed end times as tuple of integers
[(12, 0), (15, 0), (18, 0), (22, 0), (1, 0), (4, 0)]
# extracted lectures
['Physics', 'History', 'Biology', 'Chemistry', 'Computer', 'English']
# constructed dict
{'12:00-13:00': 'Physics', '15:00-16:00': 'History',
'18:00-19:00': 'Biology', '22:00-23:00': 'Chemistry',
'01:00-02:00': 'Computer', '04:00-05:00': 'English'}
# given result dict
{'12:00-13:00': 'Physics', '15:00-16:00': 'History',
'18:00-19:00': 'Biology', '22:00-23:00': 'Chemistry',
'01:00-02:00': 'Computer', '04:00-05:00': 'English'}
Комментарии:
1. Он работал с начальным словарем, но когда я изменил csv (следовательно, изменил свой словарь), я получаю тот же результат, что и начальный dict, до
2. @Cool не уверен, что ты имеешь в виду. Я отредактировал, чтобы также включить часть протокола как часть решения.
3. @Cool В качестве времени начала физики используется время окончания математики, все новые лекции длятся 1 час. Он использует старое время начала физики для истории, а также имеет длину 1 час и т.д.
4. Он работает с этой логикой, но я попытался изменить временной интервал, и это не сработало, так что было любопытно, в любом случае, спасибо за этот ответ с 0 импортами, отлично! Я смог лучше понять понимание вложенного списка.