Анализ клиентов в Python

Я хочу узнать общие расходы клиента и общие расходы, понесенные на дату, из двух словарей.

def analysis(file: str, customer: str, date: str) -> (float, float):
    try:
        with open(file, 'r') as filehand:
            for row in filehand:
                print(row)r]
            else:
                return "Name not found"
            if date in dates:
                date_expense = dates[date]
            else:
                return "Date not found"
    except:
        return "File not found"

Формат return print("message") Недействителен. Вы наверное хотели raise Exception("message")

flakes 25.09.2023 08:56

@flakes, спасибо! я исправил эту часть, хотя в целом все еще не получаю правильных результатов.

soccergirlylegends9 25.09.2023 09:04

Обратите внимание, что «csv» не является «внешней библиотекой», а является частью стандартной библиотеки.

Abdul Aziz Barkat 25.09.2023 14:05
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
3
93
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вам нужно разделить каждую строку?

rows = [row.split(',') for row in filehand]
customer_name = {row[0]:int(row[2]) for row in rows}
dates = {row[3]:int(row[2]) for row in rows}

Не разделяя каждую входную строку, оператор [] извлекает отдельные элементы из строк.

это действительно помогло огромное спасибо! Я все еще получаю одну неправильную ошибку в автогрейдере. я обновил свой код в OG, есть ли у вас какие-либо предложения?

soccergirlylegends9 25.09.2023 20:28
Ответ принят как подходящий

У меня плохие новости. Здесь вы допустили почти все возможные ошибки :)

Во-первых, считается плохой практикой использовать только оператор except:, вам следует проверять конкретные типы исключений, чтобы не пропустить ошибки в своем коде. О типах исключений в Python вы можете прочитать там.

Плохой:

except:     # catches all possible errors
    return "File not found"

Хороший:

except OSError:     # catches only OS errors such as "file not found", "disk full", etc.
    return "File not found"

В частности, поскольку вы использовали except:, вы не заметили эту ошибку:

return customer_name.get(name, "Name not found")

Вы используете аргумент customer для имени клиента, а не name, и это вызывает исключение, которое не было перехвачено.

Затем возникает проблема с чтением файла:

customer_name = {rows[0]:rows[2] for rows in filehand}
dates = {rows[3]:rows[2] for rows in filehand}

rows[N] дает вам N-й символ из строки файла, чего вы не хотите. Итак, результаты:

>>> customer_name
{'A': 'i', 'S': 's', 'N': 'c', 'M': 'c'}
>>> dates
{}

dates — это просто {}, потому что вы уже прочитали весь файл, чтобы построить customer_name дикт.

Чтобы создать строки данных, вам следует сначала разделить строку, а затем создать словари. Вот так (@SmellyCat также упомянул об этом в своем ответе):

rows = [row.strip().split(',') for row in filehand]
customer_name = {row[0]: row[2] for row in rows}
dates = {row[3]: row[2] for row in rows}

В любом случае, использование dict-понимания - плохая идея, потому что оно не дает того, что вы ожидали:

>>> customer_name
{'Alice White': '600', 'Susan Green': '500', 'Nick Hanes': '500', 'Michael Jones': '155'}

Как видите, для каждого клиента сохраняется только последняя запись данных. Но мы хотим получить суммы. Поэтому нам нужен другой подход. Например, мы могли бы использовать модуль defaultdict from collections для агрегирования значений для каждого клиента/даты. Подробнее о defaultdict там.

customer_name = defaultdict(float)    # set the 0.0 value when the key is missed
dates = defaultdict(float)
for row in rows:
    name = row[0]
    amount = float(row[2])    # need to convert amount to float type
    sale_date = row[3]
    customer_name[name] += amount
    dates[sale_date] += amount

(Отредактировано) Вы также можете реализовать это с помощью простого dict. Если да, то вам следует добавить блок try/except, чтобы выявить возможные ключевые ошибки:

customer_name = {}
dates = {}
for row in rows:
    name = row[0]
    amount = float(row[2])
    sale_date = row[3]
    try:
        customer_name[name] += amount
    except KeyError:     # If name is not present in the dictionary
        customer_name[name] = amount
    try:
        dates[sale_date] += amount
    except KeyError:     # If date is not present in the dictionary
        dates[sale_date] = amount

Хорошо, у нас есть словари. Давайте проверим, есть ли в них customer или date. Строки ниже не работают, потому что some_dict.items() дает вам список кортежей (key, value), поэтому вы, очевидно, не найдете в нем ни одного str, потому что str не является tuple. Это всегда подарит вам False. В этом случае вы можете просто найти ключ в самом словаре, как он ищет ключи по умолчанию.

Не работай

if customer in customer_name.items():
if date in dates.items():

Работает хорошо:

if customer in customer_name:
if date in dates:

Итак, мы находим наши customer/date в наших словарях. Но мы сталкиваемся с другой проблемой. Эти строки дают нам сумму всех расходов, а не конкретного customer/date.

customer_expense = sum(list(customer_name.values()))
date_expense = sum(list(dates.values()))

Чтобы получить расход для конкретного customer, мы можем просто использовать customer_name[customer] и аналогично для date. А в блоке else мы просто возвращаем нужную строку.

Вместо этого:

if customer in customer_name.items():
    customer_expense = sum(list(customer_name.values()))
else:
    return customer_name.get(name, "Name not found")

Сделай это:

if customer in customer_name:
    customer_expense = customer_name[customer]
else:
    return "Name not found"

Полный код выглядит следующим образом (реализация с использованием обычного dict):

def customer_analysis(filename: str, customer: str, date: str) -> (float, float):
    try:
        with open(filename, 'r') as filehand:
            rows = [row.strip().split(',') for row in filehand]
            customer_name = {}
            dates = {}
            for row in rows:
                name = row[0]
                amount = float(row[2])
                sale_date = row[3]
                customer_name.setdefault(name, 0.0)
                customer_name[name] += amount
                dates.setdefault(sale_date, 0.0)
                dates[sale_date] += amount

        if customer in customer_name:
            customer_expense = customer_name[customer]
        else:
            return "Name not found"
        if date in dates:
            date_expense = dates[date]
        else:
            return "Date not found"
    except OSError:
        return "File not found"

    return customer_expense, date_expense

И для ваших входных данных возвращается, как и ожидалось:

>>> customer_analysis(filename=filename, customer='Alice White', date='2023-09-05')
(615.0, 170.0)

Если имя не найдено в файле:

>>> customer_analysis(filename=filename, customer='Somebody', date='2023-09-05')
Name not found

Если дата не найдена:

>>> customer_analysis(filename=filename, customer='Alice White', date='1492-10-13')
Date not found

привет! Спасибо! есть ли способ сделать это без импорта defaultdict?

soccergirlylegends9 25.09.2023 20:19

Конечно! Вы можете использовать блок try/except для имитации поведения defaultdict. Я обновил ответ, добавив эту реализацию

Vitaly Kovalev 25.09.2023 21:04

Можете ли вы уточнить, какой код вы тестировали? Тот, о котором сейчас идет речь, или что-то другое? «Файл не найден» будет отображаться в моем варианте кода только в том случае, если функция получает неправильное имя файла, поэтому очень странно видеть этот результат так часто.

Vitaly Kovalev 25.09.2023 21:24

Код, который сейчас находится в вашем вопросе, даст неверный результат, если для одного человека или даты имеется несколько записей.

Vitaly Kovalev 25.09.2023 21:28

Нет необходимости использовать метод .get(). Вы можете просто изменить код в соответствии с моим примером кода в конце моего ответа. Я не вижу никаких проблем с этим кодом

Vitaly Kovalev 25.09.2023 21:45

Ах, это странно. У меня нет проблем запустить это на моем компьютере. Я снова обновляю пример кода в своем ответе, исключая некоторые утверждения try/except. Может быть, это поможет

Vitaly Kovalev 25.09.2023 22:05

Правильно ли я понимаю, что вам нужно возвращать только «Имя не найдено», когда в файле нет имени, а не («Имя не найдено», 170) tuple?

Vitaly Kovalev 25.09.2023 22:07

я должен вернуть «Имя не найдено», если заданное имя отсутствует в файле данных!

soccergirlylegends9 25.09.2023 22:11

ваш обновленный код работал! Спасибо!

soccergirlylegends9 25.09.2023 22:14

Вау, здорово! Я удивлен, что такое изменение имеет значение :) Все вопросы по автогрейдеру верны?

Vitaly Kovalev 25.09.2023 22:18

да! было 3 теста и он прошел все 3

soccergirlylegends9 25.09.2023 22:21

Прохладный! Не могли бы вы тогда отметить мой ответ как принятый? Итак, этот вопрос будет закрыт.

Vitaly Kovalev 25.09.2023 22:26

Другие вопросы по теме