Skip to content

Instantly share code, notes, and snippets.

@strpc
Last active May 31, 2020 15:53
Show Gist options
  • Save strpc/6f8734e3da2787db310547409631bc90 to your computer and use it in GitHub Desktop.
Save strpc/6f8734e3da2787db310547409631bc90 to your computer and use it in GitHub Desktop.
csv_counter

csv_counter


Тестовое задание:

Напишите скрипт, получающий в качестве аргумента путь к CSV-файлу и выдающий в STDOUT следующее:
- посчитать общий профит с точностью до цента
- найти самые лучшие продукты по продажам, по количеству продаж и по профиту соответственно
- найти самые худшие продукты по продажам, по количеству продаж и по профиту соответственно
- найти средний срок доставки товара клиенту
- найти стандартное отклонение от среднего срока доставки товара клиенту
- посчитать и вывести в CSV-файл продажи, количество продаж и профит по каждому продукту

Python >= 3.7

Запуск:

git clone https://github.com/strpc/csv_counter.git
python3 script.py --path Order.csv

Результат: csv-файл result.csv + вывод в консоль

Общий профит:                                            286397.0217000013
Лучшие продукты по продажам:                             Canon imageCLASS 2200 Advanced Copier(61599.824)
Лучшие продукты по количеству продаж:                    Staples(215 шт)
Лучшие продукты по профиту:                              Canon imageCLASS 2200 Advanced Copier(25199.928000000004)
Худшие продукты по продажам:                             Eureka Disposable Bags for Sanitaire Vibra Groomer I Upright Vac(1.624)
Худшие продукты по количеству продаж:                    Bush Saratoga Collection 5-Shelf Bookcase, Hanover Cherry, *Special Order(1 шт)
Худшие продукты по профиту:                              Cubify CubeX 3D Printer Double Head Print(215)
Средний срок доставки:                                   3 days, 22:59:46.311787
Стандартное отклонение от среднего срока доставки:       1 day, 17:56:29.766161
import argparse
from dataclasses import dataclass
import csv
from datetime import datetime, timedelta
from collections import Counter
import statistics
from typing import List, Dict, Tuple
@dataclass
class Order:
total_profit = 0
order_date: str
ship_date: str
product_name: str
sales: str
quantity: str
discount: str
profit: str
__slots__ = (
'order_date', 'ship_date', 'product_name',
'sales', 'quantity', 'discount', 'profit'
)
def __post_init__(self):
self.order_date = self._date_from_string(self.order_date)
self.ship_date = self._date_from_string(self.ship_date)
self.sales = self._float_from_string(self.sales)
self.quantity = int(self.quantity)
self.discount = self._float_from_string(self.discount)
self.profit = self._float_from_string(self.profit)
def _date_from_string(self, date=None):
if date is None:
return datetime.strptime('11/26/90', '%m/%d/%y').date()
new_date = datetime.strptime(date, '%m/%d/%y')
return new_date.date()
def _float_from_string(self, string):
return float(string.replace(',', '.'))
def read_file(path: str = None) -> List:
if path is None:
return False
orders = []
with open(path, 'r') as f:
reader = csv.DictReader(f, delimiter=';')
for row in reader:
orders.append(Order(
order_date=row["Order Date"],
ship_date=row["Ship Date"],
product_name=row["Product Name"],
sales=row["Sales"],
quantity=row["Quantity"],
discount=row["Discount"],
profit=row["Profit"])
)
Order.total_profit += float(row["Profit"].replace(',', '.'))
return orders
def count_totals(orders: List = None) -> Tuple:
if orders is None:
return False
total_sales = Counter()
total_quantity = Counter()
total_profit = Counter()
total_delivery = timedelta()
all_times = []
for order in orders:
total_sales[order.product_name] += order.sales
total_quantity[order.product_name] += order.quantity
total_profit[order.product_name] += order.profit
total_delivery += (order.ship_date - order.order_date)
all_times.append(int((order.ship_date - order.order_date).days))
avg_deliv = total_delivery / len(orders)
stand_dev_deliv = statistics.stdev(all_times)
del orders, all_times, total_delivery
ordered_sales = sorted(dict(total_sales).items(), key=lambda item: item[1])
bad_sales = {ordered_sales[0][0]: ordered_sales[0][1]}
good_sales = {ordered_sales[-1][0]: ordered_sales[-1][1]}
del ordered_sales
ordered_quantity = sorted(
dict(total_quantity).items(), key=lambda item: item[1])
bad_quantity = {ordered_quantity[0][0]: ordered_quantity[0][1]}
good_quantity = {ordered_quantity[-1][0]: ordered_quantity[-1][1]}
del ordered_quantity
ordered_profit = sorted(dict(total_profit).items(),
key=lambda item: item[1])
bad_profit = {ordered_profit[0][0]: ordered_profit[0][1]}
good_profit = {ordered_profit[-1][0]: ordered_profit[-1][1]}
del ordered_profit
return (
good_sales, good_quantity, good_profit, bad_sales,
bad_quantity, bad_profit, avg_deliv, timedelta(stand_dev_deliv),
total_sales, total_quantity, total_profit
)
def count_obj(
total_sales: Dict = None,
total_quantity: Dict = None,
total_profit: Dict = None
) -> List:
if None in (total_sales, total_quantity, total_profit):
return False
result = []
for product, sales in total_sales.items():
result.append(
{
'name': product,
'total_sales': total_sales.get(product, None),
'total_quantity': total_quantity.get(product, None),
'total_profit': total_profit.get(product, None)
}
)
return result
def write_csv(data: List):
fieldnames = ['name', 'total_sales', 'total_quantity', 'total_profit']
with open('result.csv', 'w') as f:
writer = csv.DictWriter(f, fieldnames=fieldnames, delimiter=";")
writer.writeheader()
writer.writerows(data)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument(
'--path', nargs='?', default='Orders.csv', help='Путь к CSV-файлу.'
)
args = parser.parse_args()
try:
list_orders = read_file(args.path)
except:
print('Произошла ошибка. Укажите аргументом "--path" путь к файлу '
'или, если программа лежит в папке с CSV-файлом, хотя бы имя '
'файла(с расширением).')
exit()
if list_orders:
(good_sales, good_quantity, good_profit, bad_sales, bad_quantity,
bad_profit, avg_deliv, stand_dev_deliv, total_sales, total_quantity,
total_profit) = count_totals(list_orders)
if (total_sales, total_quantity, total_profit):
data = count_obj(
dict(total_sales),
dict(total_quantity),
dict(total_profit)
)
if data:
write_csv(data)
else:
raise ('Что-то пошло не так')
print(f"Общий профит: \t\t\t\t\t\t {Order.total_profit}")
print(
f"Лучшие продукты по продажам: \t\t\t\t "
f"{''.join((good_sales.keys()))}",
end=''
)
print(f"({list((good_sales.values()))[0]})")
print(
f"Лучшие продукты по количеству продаж: \t\t\t "
f"{''.join((good_quantity.keys()))}",
end=''
)
print(f"({list((good_quantity.values()))[0]} шт)")
print(
f"Лучшие продукты по профиту: \t\t\t\t "
f"{''.join((good_profit.keys()))}",
end=''
)
print(f"({list((good_profit.values()))[0]})")
print(
f"Худшие продукты по продажам: \t\t\t\t "
f"{''.join((bad_sales.keys()))}",
end=''
)
print(f"({list((bad_sales.values()))[0]})")
print(
f"Худшие продукты по количеству продаж: \t\t\t "
f"{''.join((bad_quantity.keys()))}",
end=''
)
print(f"({list((bad_quantity.values()))[0]} шт)")
print(
f"Худшие продукты по профиту: \t\t\t\t "
f"{''.join((bad_profit.keys()))}",
end=''
)
print(f"({list((good_quantity.values()))[0]})")
print(f"Средний срок доставки: \t\t\t\t\t {avg_deliv}")
print(
f"Стандартное отклонение от среднего срока доставки: \t "
f"{stand_dev_deliv}"
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment