Основной проблемой здесь является формат, в котором предоставляются данные.Кортеж (day,time)
как ключ к dict затрудняет индексацию dict, чтобы получить требуемое значение для каждой комбинации день / время.Как показано в приведенном ниже коде, это можно исправить, преобразовав данные в dict, который можно индексировать как data[day][time]
, возвращая процент истинных значений.Использование defaultdict
, о котором вы уже упоминали в своем вопросе, позволяет избежать необходимости заполнять нули пропущенными значениями.
Вычисление процентного значения для данного списка логических значений можно выполнить с помощью sum
: каждый True
считается как один, а каждый False
как ноль.Разделите на длину, чтобы получить среднее значение, и умножьте на 100, чтобы получить процент.Я использовал sum(bool(v) for v in lst)
в случае, если передаются некоторые не-bool значения (например, целые числа). Если вы хотите, вы можете изменить его на sum(lst)
.
Вывод кода ниже соответствует желаемому выводу.
from collections import defaultdict
# The example data.
data = {
('Montag', '17.30'): [True, False],
('Dienstag', '16.30'): [True, False],
('Mittwoch', '15.30'): [True, False],
('Donnerstag', '14.30'): [True, False, False, True],
('Freitag', '13.30'): [True, False],
('Samstag', '12.30'): [True, False],
('Sonntag', '11.30'): [True, False],
('Sonntag', '17.30'): [False, True],
('Samstag', '16.30'): [False, True],
('Freitag', '15.30'): [False, True],
('Mittwoch', '13.30'): [False, True],
('Dienstag', '12.30'): [False, True],
('Montag', '11.30'): [False, True],
('Donnerstag', '16.30'): [False, True],
('Samstag', '11.25'): [True,True]
}
# Week days, in order.
WEEK_DAYS = [
"Montag",
"Dienstag",
"Mittwoch",
"Donnerstag",
"Freitag",
"Samstag",
"Sonntag"
]
# Given a list of values, return the percentage that are truthy.
def percentage_true(lst):
return 100 * sum(bool(v) for v in lst) / len(lst)
# The list of days and times present in the data.
present_days = list(set(k[0] for k in data.keys()))
present_times = list(set(k[1] for k in data.keys()))
# Sort these days based on WEEK_DAYS.
present_days.sort(key = WEEK_DAYS.index)
# Sort the times by converting to minutes.
present_times.sort(key = lambda s: 60 * int(s[:2]) + int(s[3:]))
# Re-organize the data such that it can be indexed as
# data[day][time] => percentage. Use a defaultdict to
# return 0 for absent values.
data = {
day: defaultdict(lambda: 0, {
k[1]: percentage_true(v)
for k, v in data.items() if k[0] == day
})
for day in set(k[0] for k in data.keys())
}
# Print the header.
for day in present_days:
print(day, end=" ")
print()
# For printing, find the lengths of the day names, and the
# formats required for .format().
day_lengths = [len(s) for s in present_days]
perc_formats = ["{{:<{}.0f}}".format(l) for l in day_lengths]
# Print the values row-by-row.
for time in present_times:
for day, fmt in zip(present_days, perc_formats):
print(fmt.format(data[day][time]), end=" ")
print(time)