diff --git "a/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" "b/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" index 82b46bcf..0be4bcb8 100644 --- "a/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" +++ "b/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" @@ -25,3 +25,131 @@ Предприятия, с прибылью ниже среднего значения: Копыта """ +from collections import namedtuple +from operator import itemgetter, attrgetter +from statistics import mean + +Corp = namedtuple('Corporation', 'name qr total') + +num_corp = int(input('Введите количество предприятий для расчета прибыли: ')) + +data = [] +for _ in range(num_corp): + corp_name = input('Введите название предприятия: ') + rev_inp = input( + 'Через пробел введите прибыль' + + 'данного предприятия за каждый квартал\n' + + '(Всего 4 квартала): ') + + qr = [float(f) for f in rev_inp.split(' ')] + data.append(Corp(corp_name, qr, sum(qr))) + +aver = mean(c.total for c in data) + +data.sort(key=attrgetter('total')) +print(f'Средняя годовая прибыль всех предприятий: {aver:.2f}') +print( + 'Предприятия, с прибылью выше среднего значения:', + ' '.join(c.name for c in data if c.total >= aver)) +print( + 'Предприятия, с прибылью ниже среднего значения:', + ' '.join(c.name for c in data if c.total < aver)) + +# --- +# Введите количество предприятий для расчета прибыли: 2 +# Введите название предприятия: Рога +# Через пробел введите прибыль данного предприятия за каждый квартал +# (Всего 4 квартала): 235 345634 55 235 +# Введите название предприятия: Копыта +# Через пробел введите прибыль данного предприятия за каждый квартал +# (Всего 4 квартала): 345 34 543 34 +# Средняя годовая прибыль всех предприятий: 173557.50 +# Предприятия, с прибылью выше среднего значения: Рога +# Предприятия, с прибылью ниже среднего значения: Копыта +# --- + +# вариант, когда данные лежат в csv-файле +csvtext = """\ +Company,Q1,Q2,Q3,Q4 +SAUDI ARABIAN OIL COMPANY,62.47,25.37,44.2,51.75 +APPLE,11.25,11.25,12.67,28.75 +MICROSOFT CORPORATION,10.75,11.2,13.89,15.46 +ALPHABET,6.84,6.96,11.24,15.23 +AMAZON.COM,2.54,5.24,6.33,13.18 +FACEBOOK,4.9,5.18,7.84,11.22 +ALIBABA GROUP HOLDING,3.16,46.43,26.52,79.43 +BERKSHIRE HATHAWAY,29.16,-49.75,26.29,30.41 +TENCENT,20.38,21.58,28.89,30.15 +J P MORGAN CHASE & CO,2.85,4.68,9.44,12.1""" + +data = sorted( + ( + (n, sum(map(float, d))) + for n, *d in ( + row.split(',') + for i, row in enumerate(csvtext.split('\n')) + if i > 0)), + key=itemgetter(1), reverse=True) +aver = mean(map(itemgetter(1), data)) + +print(f'Среднее значение годовой прибыли: {aver:.2f} млрд. USD') +print() +print('Компании, заработавшие больше среднего:') +print('\n'.join(f'{n}: {v:.2f}' for n, v in data if v >= aver)) +print() +print('Компании, заработавшие меньше среднего:') +print('\n'.join(f'{n}: {v:.2f}' for n, v in data if v < aver)) +print() +# --- +# Среднее значение годовой прибыли: 71.74 млрд. USD +# +# Компании, заработавшие больше среднего: +# SAUDI ARABIAN OIL COMPANY: 183.79 +# ALIBABA GROUP HOLDING: 155.54 +# TENCENT: 101.00 +# +# Компании, заработавшие меньше среднего: +# APPLE: 63.92 +# MICROSOFT CORPORATION: 51.30 +# ALPHABET: 40.27 +# BERKSHIRE HATHAWAY: 36.11 +# FACEBOOK: 29.14 +# J P MORGAN CHASE & CO: 29.07 +# AMAZON.COM: 27.29 +# --- + +# Это решение задачи на pandas +import pandas +from io import StringIO +qr = pandas.read_csv(StringIO(csvtext)) +qr['Y2020'] = qr[['Q1', 'Q2', 'Q3', 'Q4']].sum(axis=1) +qr.sort_values('Y2020', ascending=False, inplace=True) +aver = qr['Y2020'].mean() + +print(f'Среднее значение годовой прибыли: {aver:.2f} млрд. USD') +print() +print('Компании, заработавшие больше среднего:') +print(qr[qr.Y2020 >= aver][['Company', 'Y2020']].to_string(index=False)) +print() +print('Компании, заработавшие меньше среднего:') +print(qr[qr.Y2020 < aver][['Company', 'Y2020']].to_string(index=False)) +print() +# --- +# Среднее значение годовой прибыли: 71.74 млрд. USD +# +# Компании, заработавшие больше среднего: +# Company Y2020 +# SAUDI ARABIAN OIL COMPANY 183.79 +# ALIBABA GROUP HOLDING 155.54 +# TENCENT 101.00 +# +# Компании, заработавшие меньше среднего: +# Company Y2020 +# APPLE 63.92 +# MICROSOFT CORPORATION 51.30 +# ALPHABET 40.27 +# BERKSHIRE HATHAWAY 36.11 +# FACEBOOK 29.14 +# J P MORGAN CHASE & CO 29.07 +# AMAZON.COM 27.29 +# --- diff --git "a/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" "b/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" index 35add0f1..c5e64264 100644 --- "a/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" +++ "b/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" @@ -11,3 +11,171 @@ Также попробуйте решить задачу вообще без collections и применить только ваши знания по ООП (в частности по перегрузке методов) """ + +from collections import deque + +HEXES = list('0123456789ABCDEF') +INTS = { + '0': 0, '1': 1, '2': 2, '3': 3, + '4': 4, '5': 5, '6': 6, '7': 7, + '8': 8, '9': 9, 'A': 10, 'B': 11, + 'C': 12, 'D': 13, 'E': 14, 'F': 15} + + +# я знаю про int(x, 16), но в изобретении велосипеда +# надо быть последовательным +def hex2int(hex): + return sum(16**i * INTS[d] for i, d in enumerate(reversed(hex))) + + +def int2hex(hex, base=16): + # хотя можно было обойтись reversed(list) + ret = deque() + while True: + if hex == 0: + break + ret.appendleft(HEXES[hex % base]) + hex //= base + return list(ret) + + +class Hex: + def __init__(self, arg): + if isinstance(arg, int): + self.digits = int2hex(arg) + elif isinstance(arg, str): + self.digits = list(arg.upper()) + elif isinstance(arg, list): + self.digits = [d.upper() for d in arg] + else: + raise ValueError("Invalid initialization type") + + def __repr__(self): + return f'Hex({repr(self.digits)})' + + def __str__(self): + return ''.join(self.digits) + + def __int__(self): + return hex2int(self.digits) + + def __add__(self, other): + return Hex(int(self) + int(other)) + + def __mul__(self, other): + return Hex(int(self) * int(other)) + + +h1 = Hex('A2') +h2 = Hex('C4F') +print(h1 + h2) +print(h1 * h2) +# --- +# CF1 +# 7C9FE +# --- + +# Если выше была просто необязательная часть, то дальше уже +# полная отсебятина. Теперь калькулятор разбирает целую строчку. +# Создание мини-языка по моему мнению является одним из +# полезнейших упражнений для освоения алгоритмов и +# структур данных. Если бы в geekbrains практиковались +# курсовые работы, я выбрал бы эту тему. + +# Пример работы: +# > 7+7 +# 7 + 7 = E +# > 7*7 +# 7 * 7 = 31 +# > dead + beef +# DEAD + BEEF = 19D9C + + +class HexParser: + def __init__(self): + self.digits = [] + self.hex = None + + def __bool__(self): + return bool(self.digits) + + def __str__(self): + return str(self.digits) + + def accept(self, c): + if c in INTS: + self.digits.append(c) + return True + else: + if bool(self): + self.hex = Hex(self.digits) + return False + + +OPS = { + '+': lambda x, y: x + y, + '*': lambda x, y: x * y +} + + +class OpParser: + def __init__(self): + self.sym = None + self.op = None + + def __bool__(self): + return self.sym is not None + + def __str__(self): + return str(self.sym) + + def accept(self, c): + if (self.sym is None) and (c in OPS): + self.sym = c + self.op = OPS[c] + return True + return False + + +def parse(stream, parsers): + for p in parsers: + while True: + try: + c = stream.popleft() + if not p.accept(c): + stream.appendleft(c) + break + except IndexError: + p.accept('') + break + + +class Calc: + def __init__(self): + print('Type "exit" to quit') + + def loop(self, inp): + if inp == 'exit': + return False + # Это грамматика языка, пока лишь последовательность элементов + grammar = [HexParser(), OpParser(), HexParser()] + # В настоящем языке должны быть две очереди: + # символы -> токены -> AST + # Здесь же только одна очередь + stream = deque(inp.replace(' ', '').upper()) + parse(stream, grammar) + h1, op, h2 = grammar + if all(grammar): + # Здесь должна быть обработка AST, но у меня пока + # только обработка последовательности + print( + f'{h1.hex} {op.sym} {h2.hex} = ' + + str(Hex(op.op(int(h1.hex), int(h2.hex))))) + else: + print("Ошибка в выражении") + return True + + +calc = Calc() +while calc.loop(input('> ')): + pass diff --git "a/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" "b/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" index dd1c82f3..06bdfecb 100644 --- "a/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" +++ "b/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" @@ -9,4 +9,104 @@ Выполните различные операции с каждым из объектов. Сделайте замеры и оцените, насколько информация в документации соответствует дейстивтельности. -""" \ No newline at end of file +""" + +from timeit import timeit +from collections import deque +from random import seed, randint + + +NUM_RUNS = 1000 + +SIZE = 1000000 +IDX = SIZE//2 + +seed(1) +arr0 = [randint(1, 100) for i in range(SIZE)] + +arr = list(arr0) +print("Извлекаем значения из середины списка") +print(timeit("_ = arr[IDX]", globals=globals(), number=NUM_RUNS)) + +deq = deque(arr0) +print("Извлекаем значения из середины дека") +print(timeit("_ = deq[IDX]", globals=globals(), number=NUM_RUNS)) + + +N = 10000 +seed(1) +arr0 = [randint(1, 100) for i in range(SIZE)] + +arr = list(arr0) +print("Вставляем значения в голову списка") +print(timeit("arr.insert(500, 0)", globals=globals(), number=NUM_RUNS)) + +arr = deque(arr0) +print("Добавляем значения в хвост списка") +print(timeit("arr.append(500)", globals=globals(), number=NUM_RUNS)) + +deq = deque(arr0) +print("Вставляем значения в голову дека") +print(timeit("deq.insert(500, 0)", globals=globals(), number=NUM_RUNS)) + +deq = deque(arr0) +print("Добавляем значения в голову дека") +print(timeit("deq.appendleft(500)", globals=globals(), number=NUM_RUNS)) + +deq = deque(arr0) +print("Добавляем значения в хвост дека") +print(timeit("deq.append(500)", globals=globals(), number=NUM_RUNS)) +# --- +# Извлекаем значения из середины списка +# 6.176996976137161e-05 +# Извлекаем значения из середины дека +# 0.08101026999065652 +# Вставляем значения в голову списка +# 0.9436411040369421 +# Добавляем значения в хвост списка +# 6.619800115004182e-05 +# Вставляем значения в голову дека +# 0.0009685130207799375 +# Добавляем значения в голову дека +# 9.289098670706153e-05 +# Добавляем значения в хвост дека +# 6.085203494876623e-05 +# --- + +# Самый предсказуемый результат -- добавление в хвост +# как списка, так и дека примерно одинаково по времени +# и очень бысто, согласно документации O(1). + +# Про добавление в голову и хвост дека в документации написано +# approximately the same O(1) performance in either direction, +# что тоже подтверждается. + +# Про существенное отличие скорости произвольного доступа +# к списку и деку не написано ничего, но оно есть (для 1000000 +# элементов более, чем в 1000 раз). + +# Для коллекций из 10000 элементов вставка в начало списка +# происходит в 100 раз медленнее, чем добавление в начало дека +# через deque.appendleft(). Про list в документации написано +# incur O(n) memory movement costs for pop(0) and insert(0, v) +# что мы и наблюдаем. + +# Теперь исследуем удивительную особенность дека, результаты операций +# insert(0, x) и appendleft(x) равны, однако их время выполнения +# различается почти в 10 раз: +d1 = deque([3, 2, 1]) +d2 = deque(d1) +print(d1 == d2) +# --- +# True +# --- +d1.insert(0, 4) +d2.appendleft(4) +print(d1 == d2) +# --- +# True +# --- +# Предположительно из-за того, что insert сдвигает содержимое, +# чтобы освободить место для нового элемента, а appendleft +# добавляет элемент в резервную область пямяти, содержимое +# дека остается на месте. diff --git "a/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" "b/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" index 13ec157f..8e8c1337 100644 --- "a/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" +++ "b/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" @@ -3,4 +3,108 @@ Поработайте с обычным словарем и OrderedDict. Выполните различные операции с каждым из объектов и сделайте замеры. Опишите полученные результаты, сделайте выводы. -""" \ No newline at end of file +""" + +from collections import OrderedDict +from random import seed, randint +from time import process_time + +seed(1) +DEGREE = (5, 6, 7) +builtin_dicts = {'name': 'builtin_dict'} +ordered_dicts = {'name': 'ordered_dict'} +# Создадим несколько словарей разных размеров, +# чтобы иметь возможность оценивать O() +for k in DEGREE: + d = { + # Заполняем словарь строковыми ключами + str(n := randint(100000, 1000000)): n + for _ in range(10**k)} + builtin_dicts[k] = d + ordered_dicts[k] = OrderedDict(d) + +data = [builtin_dicts, ordered_dicts] + +methods = [ + ("__setitem__", 2), + ("__getitem__", 1), + ("__delitem__", 1)] + +num_runs = 10**6 +d = builtin_dicts +for (fun_name, num) in methods: + for d in data: + print(f'{d["name"]}, {fun_name}') + for k in DEGREE: + size = 10 ** k + print(f'{size} элементов') + met = getattr(d[k], fun_name) + start = process_time() + for i in range(num_runs): + args = (str(i), i)[:num] + met(*args) + dt = process_time() - start + print(f'{size}: {dt}') + print() + +# --- +# builtin_dict, __setitem__ +# 100000 элементов +# 100000: 0.6716675999999993 +# 1000000 элементов +# 1000000: 0.7608359580000013 +# 10000000 элементов +# 10000000: 0.7604866769999994 +# +# ordered_dict, __setitem__ +# 100000 элементов +# 100000: 0.8217655059999984 +# 1000000 элементов +# 1000000: 0.913207314000001 +# 10000000 элементов +# 10000000: 0.8177587049999993 +# +# builtin_dict, __getitem__ +# 100000 элементов +# 100000: 0.5964190340000002 +# 1000000 элементов +# 1000000: 0.6935882549999981 +# 10000000 элементов +# 10000000: 0.742809373 +# +# ordered_dict, __getitem__ +# 100000 элементов +# 100000: 0.6058348170000016 +# 1000000 элементов +# 1000000: 0.7125418229999987 +# 10000000 элементов +# 10000000: 0.7536874749999996 +# +# builtin_dict, __delitem__ +# 100000 элементов +# 100000: 0.5940442270000013 +# 1000000 элементов +# 1000000: 0.712487785999997 +# 10000000 элементов +# 10000000: 0.7481913849999984 +# +# ordered_dict, __delitem__ +# 100000 элементов +# 100000: 0.6545065669999985 +# 1000000 элементов +# 1000000: 0.828653580000001 +# 10000000 элементов +# 10000000: 0.9702847160000019 +# --- + +# Обе структуры показывают поразительно +# слабую зависимость времени операции +# от размера коллекции (а в случае записи +# вообще отсутствие такой зависимости). +# +# Главным выводом можно считать практически +# полное соответствие по времени обеих коллекций +# с незначительным выигрышем встроенных словарей. +# Таким образом нет явной причины использовать +# OrderedDict за исключением +# поддержки legacy-кода