Skip to content

Homework2 fully done#1

Open
kturkin wants to merge 1 commit intomainfrom
Homework2
Open

Homework2 fully done#1
kturkin wants to merge 1 commit intomainfrom
Homework2

Conversation

@kturkin
Copy link
Copy Markdown
Owner

@kturkin kturkin commented Mar 17, 2025

No description provided.

Copy link
Copy Markdown

@0xE111 0xE111 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Всё хорошо, но бонусное хорошо было бы переделать там где рекурсия. Но т.к. оно бонусное, то по желанию.

Comment thread .gitignore
@@ -0,0 +1 @@
env
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Обычно это файл .env (с точкой впереди)

Comment thread for_challenges.py
names = ['Оля', 'Петя', 'Вася', 'Маша']
# ???
for name in names:
gender = 'М' if is_male[name] else 'Ж'
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Чётко!

Comment thread for_dict_challenges.py
Comment on lines +30 to +33
for name in names:
for person in students_list:
if name == person:
count_dict[name] += 1
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Логика понятна, но это сильно неоптимально. Каждый проход по циклу стоит каких-то ресурсов, а тут аж цикл в цикле. Вообще вложенные циклы нужно стараться избегать, потому что пройти по циклу из N элементов - это N итераций, а по двум вложенным циклам - уже N*N - то есть квадратичная сложность.

В данном случае можно сделать что-то совсем простое, например, один раз (!) пройтись по студентам и увеличивать счётчик имени:

counter = {}
for student in students:
    name = student['first_name']
    try:
        counter[name] += 1
    except KeyError:
        counter[name] = 1

Если хочется чего-то покороче - можно посмотреть в сторону defaultdict.

Comment thread for_dict_challenges.py
Comment on lines +63 to +64
for key in counted.keys():
val = counted[key]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Если нужны и ключ, и значение, то нужно сразу

for key, val in counterd.items():
    ...

Comment thread string_challenges.py
# Вывести количество букв "а" в слове
word = 'Архангельск'
# ???
print(len(word))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это явно что-то не то :)

Comment on lines +97 to +99
def count_messages_by_key(history, key, pop_none = False):
items = list_val_by_key(history, key, pop_none = pop_none)
return count_repeated(items)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тогда это превратится в

key = 'some-key'
values = [message[key] for message in history]
counter = Counter(values)

Comment on lines +102 to +105
def find_biggest(data: dict): # {item : count}
listed_count = list(data.values()) # call values just once
most_index = listed_count.index(max(listed_count)) # get id in values list,
return list(data.keys())[most_index] # as we get the same order from keys as from values method we use the same id
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Если использовали Counter, то

biggest = counter.most_common(1)[0]

Если хочется вручную это сделать, то рекомендую просто использовать max() с аргументом key:

biggest = max(data, key=lambda x: data[x])

Текущий вариан плох тем, что что там keys() и values() вызываются, то есть как минимум дважды проходимся по словарю. Лучше уж топорный вариант с сохранением самого большого элемента, он будет всё равно оптимальнее:

def find_biggest(data: dict):
    biggest_item = None
    biggest_count = 0
    for item, count in data.items():
        if count > biggest_count:
            biggest_count = count
            biggest_item = item

    return biggest_item

Comment on lines +120 to +126
for i, divider in enumerate(time_dividers):
if hour < divider:
output[i].append(hour)
found = True
break
if not found: # means given hour is after the last divider
output[-1].append(hour)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В таких случаях вместо found = True / False нужно использовать for - else:

for item in items:
    if ...:
        print("Something good happened")
        break
else:
    print("Nothing good happened")

Comment on lines +107 to +112
def separate_datetime_by_hours(data: list, time_dividers: list):
'''
Accepts datetime list and intervals dividers,
returns a list of time lists sorted on intervals by hours
'''

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Огромное увеличение сложности, только чтобы потом красиво вызвать

separated_dates = separate_datetime_by_hours(dates, [12, 18])

Имхо не стоит того. Можно просто сделать функцию для категоризации:

def get_part_of_day(dt) -> Literal['morning', 'day', 'evening']:
    if 0 <= dt.hour < 9:
        return 'morning'
    if 9 <= dt.hour < 18:
        return 'day'
    return 'evening' 

И потом уже её использовать:

messages_by_part_of_day = {
    'morning': 0,
    'day': 0,
    'evening': 0,
}
for dt in data:
    part_of_day = get_part_of_day(dt)
    messages_by_part_of_day[part_of_day] += 1

Гораздо проще читать и понимать.

Comment on lines +181 to +189
reply_for_ids = list_val_by_key(history, 'reply_for', pop_none=True)
treads = {}

for reply_for_id in reply_for_ids:
tread = []
recursive_search_and_stack(reply_for_id, history, tread)
treads[tread[-1]] = len(tread)

longest_dialog_start_id = find_biggest(treads)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тут сначала мы полностью проходим по всем сообщениям, только чтобы собрать их reply_for, а потом в цикле for reply_for_id in reply_for_ids вызываем рекурсивную recursive_search_and_stack, которая в цикле проходит по всем сообщениям. Такой код будет работать дома на компьютере, но как только уйдёт в работу, сразу взорвётся на реальных данных, когда там будет тысяча сообщений.

Это совершенно точно нужно отрефакторить, чтобы был один, ну максимум два прохода по history, но не больше.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants