From b89224895bc363449d879af2edc76e425a7c8219 Mon Sep 17 00:00:00 2001 From: Deophius Date: Fri, 17 Jan 2025 12:58:46 +0000 Subject: [PATCH 01/11] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E9=80=89=E8=AF=BE?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E4=B8=AD=E5=AD=98=E5=9C=A8=E7=9A=84=E7=AB=9E?= =?UTF-8?q?=E4=BA=89=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 加了相应的unique constraint,并且使用原子的update_or_create,避免在数据库中产生两个相同的记录 --- app/course_utils.py | 17 +++++------------ ...rticipant_unique_course_selection_record.py | 18 ++++++++++++++++++ app/models.py | 3 +++ 3 files changed, 26 insertions(+), 12 deletions(-) create mode 100644 app/migrations/0009_courseparticipant_unique_course_selection_record.py diff --git a/app/course_utils.py b/app/course_utils.py index 9ac24dcfb..0dd623498 100644 --- a/app/course_utils.py +++ b/app/course_utils.py @@ -608,8 +608,6 @@ def registration_status_change(course_id: int, user: NaturalPerson, and course_status != Course.Status.STAGE2): return wrong("在非选课阶段不能选课!") - need_to_create = False - if action == "select": if CourseParticipant.objects.filter(course_id=course_id, person=user).exists(): @@ -617,7 +615,6 @@ def registration_status_change(course_id: int, user: NaturalPerson, course_id=course_id, person=user) cur_status = participant_info.status else: - need_to_create = True cur_status = CourseParticipant.Status.UNSELECT if course_status == Course.Status.STAGE1: @@ -681,15 +678,11 @@ def registration_status_change(course_id: int, user: NaturalPerson, course.current_participants += 1 course.save() - # 由于不同用户之间的状态不共享,这个更新应该可以不加锁 - if need_to_create: - CourseParticipant.objects.create(course_id=course_id, - person=user, - status=to_status) - else: - CourseParticipant.objects.filter( - course_id=course_id, - person=user).update(status=to_status) + CourseParticipant.objects.update_or_create( + course_id = course_id, + person = user, + defaults = {"status": to_status} + ) succeed("选课成功!", context) except: return context diff --git a/app/migrations/0009_courseparticipant_unique_course_selection_record.py b/app/migrations/0009_courseparticipant_unique_course_selection_record.py new file mode 100644 index 000000000..2d9661d6d --- /dev/null +++ b/app/migrations/0009_courseparticipant_unique_course_selection_record.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.9 on 2025-01-17 20:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("app", "0008_pool_activity_alter_poolitem_exchange_attributes_and_more"), + ] + + operations = [ + migrations.AddConstraint( + model_name="courseparticipant", + constraint=models.UniqueConstraint( + fields=("course", "person"), name="Unique course selection record" + ), + ), + ] diff --git a/app/models.py b/app/models.py index 54efa978b..8d94be1ad 100644 --- a/app/models.py +++ b/app/models.py @@ -1580,6 +1580,9 @@ class CourseParticipant(models.Model): class Meta: verbose_name = "4.课程报名情况" verbose_name_plural = verbose_name + constraints = [ + models.UniqueConstraint(fields = ['course', 'person'], name='Unique course selection record') + ] course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name="participant_set") From 2e5d4988d049721821107b275e01d7c0db782f5f Mon Sep 17 00:00:00 2001 From: Deophius Date: Fri, 17 Jan 2025 13:42:38 +0000 Subject: [PATCH 02/11] Add course priority field in NaturalPerson --- app/admin.py | 1 + .../0010_naturalperson_course_priority.py | 17 +++++++++++++++++ app/models.py | 1 + 3 files changed, 19 insertions(+) create mode 100644 app/migrations/0010_naturalperson_course_priority.py diff --git a/app/admin.py b/app/admin.py index 5e8cbe788..19ef1691e 100644 --- a/app/admin.py +++ b/app/admin.py @@ -77,6 +77,7 @@ def get_normal_fields(self, request, obj: NaturalPerson = None): f(_m.identity), f(_m.status), f(_m.wechat_receive_level), f(_m.accept_promote), f(_m.active_score), + f(_m.course_priority) ]) return fields diff --git a/app/migrations/0010_naturalperson_course_priority.py b/app/migrations/0010_naturalperson_course_priority.py new file mode 100644 index 000000000..8fd10e8d6 --- /dev/null +++ b/app/migrations/0010_naturalperson_course_priority.py @@ -0,0 +1,17 @@ +# Generated by Django 5.0.9 on 2025-01-17 21:27 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("app", "0009_courseparticipant_unique_course_selection_record"), + ] + + operations = [ + migrations.AddField( + model_name="naturalperson", + name="course_priority", + field=models.FloatField(default=1.0, verbose_name="书院课选课权重"), + ), + ] diff --git a/app/models.py b/app/models.py index 8d94be1ad..5587cadd4 100644 --- a/app/models.py +++ b/app/models.py @@ -362,6 +362,7 @@ class ReceiveLevel(models.IntegerChoices): accept_promote = models.BooleanField(default=True) # 是否接受推广消息 active_score = models.FloatField("活跃度", default=0) # 用户活跃度 + course_priority = models.FloatField("书院课选课权重", default=1.0) # 书院课预选抽签权重 def __str__(self): return str(self.name) From 0c6537052c9ae67afc6942e71681cd65265bf00e Mon Sep 17 00:00:00 2001 From: Deophius Date: Fri, 17 Jan 2025 13:44:02 +0000 Subject: [PATCH 03/11] Weighted lot drawing --- app/course_utils.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/course_utils.py b/app/course_utils.py index 0dd623498..2969c56f0 100644 --- a/app/course_utils.py +++ b/app/course_utils.py @@ -46,7 +46,7 @@ import openpyxl import openpyxl.worksheet.worksheet -from random import sample +from numpy.random import choice from urllib.parse import quote from collections import Counter from datetime import datetime, timedelta @@ -809,7 +809,11 @@ def draw_lots(): if participants_num <= 0: continue - participants_id = list(participants.values_list("id", flat=True)) + participants_info = participants.values_list("id", "person__course_priority") + participants_id, priority = map(list, zip(*participants_info)) + # Turn priority into a probability distribution + sum_priority = sum(priority) + priority = [i / sum_priority for i in priority] capacity = course.capacity if participants_num <= capacity: @@ -821,7 +825,7 @@ def draw_lots(): current_participants=participants_num) else: # 抽签;可能实现得有一些麻烦 - lucky_ones = sample(participants_id, capacity) + lucky_ones = choice(participants_id, capacity, replace=False, p=priority) unlucky_ones = list( set(participants_id).difference(set(lucky_ones))) # 不确定是否要加悲观锁 From 06e31787da5c4b0a950f95f5e0d1023666403e33 Mon Sep 17 00:00:00 2001 From: Deophius Date: Sat, 18 Jan 2025 14:55:49 +0000 Subject: [PATCH 04/11] Manage script for course priority Remember to uncomment return in 2025 Fall --- .../commands/update_course_priority.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 app/management/commands/update_course_priority.py diff --git a/app/management/commands/update_course_priority.py b/app/management/commands/update_course_priority.py new file mode 100644 index 000000000..7236099ff --- /dev/null +++ b/app/management/commands/update_course_priority.py @@ -0,0 +1,32 @@ +from django.core.management.base import BaseCommand + +from app.models import NaturalPerson, CourseRecord +from semester.api import semester_of +from datetime import datetime, timedelta + +class Command(BaseCommand): + # This command should be run before new semester starts + help = "Updates course_priority for all NaturalPerson" + + def handle(self, *args, **options): + # Currently, just adjust all of them to 1. + NaturalPerson.objects.update(course_priority=1.0) + # Comment out this return to enable course priority + return + # Gets the semester three months ago + sem = semester_of(datetime.now() - timedelta(days=90)) + # A list of invalid record's student id. + # FIXME: This is too ugly. Try reformat after issue #869 is resolved + invalid_id = CourseRecord.objects.filter( + year=sem.year, invalid=True, + semester='Fall' if '秋' in sem.type.name else 'Spring' + ).values_list('person__id', flat = True) + # Number of times appearing in the invalid list + invalid_cnt = dict() + for i in invalid_id: + if i not in invalid_cnt.keys(): + invalid_cnt[i] = 0 + invalid_cnt[i] += 1 + for person_id in invalid_cnt: + p = max(0.5, 1 - 0.05 * invalid_cnt[person_id]) + NaturalPerson.objects.filter(id=person_id).update(course_priority=p) From 716275800177521aea48f935706c6d778c7be29b Mon Sep 17 00:00:00 2001 From: Deophius Date: Sun, 19 Jan 2025 07:20:16 +0000 Subject: [PATCH 05/11] Enhancements for update_course_priority Now accepts year + semester pair on command line. Does the sorting in the SQL query, allowing O(n) counting invalid records. Updates course priority in batch and added transaction.atomic --- .../commands/update_course_priority.py | 59 +++++++++++++------ 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/app/management/commands/update_course_priority.py b/app/management/commands/update_course_priority.py index 7236099ff..aa7d34e96 100644 --- a/app/management/commands/update_course_priority.py +++ b/app/management/commands/update_course_priority.py @@ -1,32 +1,53 @@ from django.core.management.base import BaseCommand +from django.db import transaction from app.models import NaturalPerson, CourseRecord -from semester.api import semester_of -from datetime import datetime, timedelta + +from typing import Dict, List +from tqdm import trange class Command(BaseCommand): # This command should be run before new semester starts help = "Updates course_priority for all NaturalPerson" + def add_arguments(self, parser): + parser.add_argument('year', type=int, help='year of the course records to check (required)') + parser.add_argument('semester', type=str, help='semester of the course records to check. Valid values are: Fall, Spring (required)') + + @transaction.atomic def handle(self, *args, **options): # Currently, just adjust all of them to 1. NaturalPerson.objects.update(course_priority=1.0) # Comment out this return to enable course priority - return - # Gets the semester three months ago - sem = semester_of(datetime.now() - timedelta(days=90)) + # return + if options['semester'] not in ('Fall', 'Spring'): + print('Error: must have value of "Fall" or "Spring"!') + return # A list of invalid record's student id. - # FIXME: This is too ugly. Try reformat after issue #869 is resolved - invalid_id = CourseRecord.objects.filter( - year=sem.year, invalid=True, - semester='Fall' if '秋' in sem.type.name else 'Spring' - ).values_list('person__id', flat = True) - # Number of times appearing in the invalid list - invalid_cnt = dict() - for i in invalid_id: - if i not in invalid_cnt.keys(): - invalid_cnt[i] = 0 - invalid_cnt[i] += 1 - for person_id in invalid_cnt: - p = max(0.5, 1 - 0.05 * invalid_cnt[person_id]) - NaturalPerson.objects.filter(id=person_id).update(course_priority=p) + invalid_id: List[int] = list(CourseRecord.objects.filter( + year = options['year'], invalid = True, semester = options['semester'] + ).order_by( + 'person__id' + ).values_list( + 'person__id', flat = True + )) + # Number of invalid records + n = len(invalid_id) + print(f'update_course_priority: There are {n} invalid records.') + # a[k] is the list of id of people who have k invalid records + a: Dict[int, List[int]] = dict() + # Length of the current continuous segment + k = 0 + for i in trange(n, desc = 'Processing invalid records'): + k += 1 + if i == n - 1 or invalid_id[i] != invalid_id[i + 1]: + if k not in a: + a[k] = [] + a[k].append(invalid_id[i]) + k = 0 + # Print out a summary of invalid records + for i in a: + print(f'There are {len(a[i])} people with {i} invalid records...') + p = max(0.5, 1 - 0.05 * i) + NaturalPerson.objects.filter(id__in = a[i]).update(course_priority = p) + print('Done!') \ No newline at end of file From 186301c8d59b11d330eee904d143116326cddfb9 Mon Sep 17 00:00:00 2001 From: Deophius Date: Sun, 19 Jan 2025 07:24:39 +0000 Subject: [PATCH 06/11] Merge migration files --- ...9_naturalperson_course_priority_and_more.py} | 7 ++++++- .../0010_naturalperson_course_priority.py | 17 ----------------- 2 files changed, 6 insertions(+), 18 deletions(-) rename app/migrations/{0009_courseparticipant_unique_course_selection_record.py => 0009_naturalperson_course_priority_and_more.py} (64%) delete mode 100644 app/migrations/0010_naturalperson_course_priority.py diff --git a/app/migrations/0009_courseparticipant_unique_course_selection_record.py b/app/migrations/0009_naturalperson_course_priority_and_more.py similarity index 64% rename from app/migrations/0009_courseparticipant_unique_course_selection_record.py rename to app/migrations/0009_naturalperson_course_priority_and_more.py index 2d9661d6d..284db23c7 100644 --- a/app/migrations/0009_courseparticipant_unique_course_selection_record.py +++ b/app/migrations/0009_naturalperson_course_priority_and_more.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.9 on 2025-01-17 20:52 +# Generated by Django 5.0.9 on 2025-01-19 15:23 from django.db import migrations, models @@ -9,6 +9,11 @@ class Migration(migrations.Migration): ] operations = [ + migrations.AddField( + model_name="naturalperson", + name="course_priority", + field=models.FloatField(default=1.0, verbose_name="书院课选课权重"), + ), migrations.AddConstraint( model_name="courseparticipant", constraint=models.UniqueConstraint( diff --git a/app/migrations/0010_naturalperson_course_priority.py b/app/migrations/0010_naturalperson_course_priority.py deleted file mode 100644 index 8fd10e8d6..000000000 --- a/app/migrations/0010_naturalperson_course_priority.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 5.0.9 on 2025-01-17 21:27 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("app", "0009_courseparticipant_unique_course_selection_record"), - ] - - operations = [ - migrations.AddField( - model_name="naturalperson", - name="course_priority", - field=models.FloatField(default=1.0, verbose_name="书院课选课权重"), - ), - ] From f11b99d5fc19674cb06ee6a6a2fabc3b098e7948 Mon Sep 17 00:00:00 2001 From: Deophius Date: Mon, 20 Jan 2025 03:21:38 +0000 Subject: [PATCH 07/11] Revert "Merge migration files" This reverts commit 186301c8d59b11d330eee904d143116326cddfb9. This is because the race condition resolution commit is now in another PR. --- ...rticipant_unique_course_selection_record.py} | 7 +------ .../0010_naturalperson_course_priority.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) rename app/migrations/{0009_naturalperson_course_priority_and_more.py => 0009_courseparticipant_unique_course_selection_record.py} (64%) create mode 100644 app/migrations/0010_naturalperson_course_priority.py diff --git a/app/migrations/0009_naturalperson_course_priority_and_more.py b/app/migrations/0009_courseparticipant_unique_course_selection_record.py similarity index 64% rename from app/migrations/0009_naturalperson_course_priority_and_more.py rename to app/migrations/0009_courseparticipant_unique_course_selection_record.py index 284db23c7..2d9661d6d 100644 --- a/app/migrations/0009_naturalperson_course_priority_and_more.py +++ b/app/migrations/0009_courseparticipant_unique_course_selection_record.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.9 on 2025-01-19 15:23 +# Generated by Django 5.0.9 on 2025-01-17 20:52 from django.db import migrations, models @@ -9,11 +9,6 @@ class Migration(migrations.Migration): ] operations = [ - migrations.AddField( - model_name="naturalperson", - name="course_priority", - field=models.FloatField(default=1.0, verbose_name="书院课选课权重"), - ), migrations.AddConstraint( model_name="courseparticipant", constraint=models.UniqueConstraint( diff --git a/app/migrations/0010_naturalperson_course_priority.py b/app/migrations/0010_naturalperson_course_priority.py new file mode 100644 index 000000000..8fd10e8d6 --- /dev/null +++ b/app/migrations/0010_naturalperson_course_priority.py @@ -0,0 +1,17 @@ +# Generated by Django 5.0.9 on 2025-01-17 21:27 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("app", "0009_courseparticipant_unique_course_selection_record"), + ] + + operations = [ + migrations.AddField( + model_name="naturalperson", + name="course_priority", + field=models.FloatField(default=1.0, verbose_name="书院课选课权重"), + ), + ] From fce67d2aded876faf5bbe56ce4caf5d5ce9196c2 Mon Sep 17 00:00:00 2001 From: Deophius Date: Mon, 20 Jan 2025 03:34:47 +0000 Subject: [PATCH 08/11] Style fix for script Organize imports and add trailing newline --- app/management/commands/update_course_priority.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/management/commands/update_course_priority.py b/app/management/commands/update_course_priority.py index aa7d34e96..0a7205a6a 100644 --- a/app/management/commands/update_course_priority.py +++ b/app/management/commands/update_course_priority.py @@ -1,11 +1,11 @@ +from typing import Dict, List + from django.core.management.base import BaseCommand from django.db import transaction - -from app.models import NaturalPerson, CourseRecord - -from typing import Dict, List from tqdm import trange +from app.models import CourseRecord, NaturalPerson + class Command(BaseCommand): # This command should be run before new semester starts help = "Updates course_priority for all NaturalPerson" @@ -50,4 +50,4 @@ def handle(self, *args, **options): print(f'There are {len(a[i])} people with {i} invalid records...') p = max(0.5, 1 - 0.05 * i) NaturalPerson.objects.filter(id__in = a[i]).update(course_priority = p) - print('Done!') \ No newline at end of file + print('Done!') From bd104f629684e4baa01534c6fce30f4590c0afff Mon Sep 17 00:00:00 2001 From: Deophius Date: Mon, 20 Jan 2025 04:03:31 +0000 Subject: [PATCH 09/11] Refactor update_course_priority into course_utils.py --- app/course_utils.py | 43 ++++++++++++++++ .../commands/update_course_priority.py | 50 ++++--------------- 2 files changed, 52 insertions(+), 41 deletions(-) diff --git a/app/course_utils.py b/app/course_utils.py index 2969c56f0..9baee89c2 100644 --- a/app/course_utils.py +++ b/app/course_utils.py @@ -12,6 +12,8 @@ process_time: 把datetime对象转换成人类可读的时间表示 check_course_time_conflict: 检查当前选择的课是否与已选的课上课时间冲突 """ +from typing import Callable, Dict + from app.utils_dependency import * from app.models import ( User, @@ -1486,3 +1488,44 @@ def download_select_info(single_course: Course | None = None): file_name = f'{year}{semester}选课名单汇总-{ctime}' # 保存并返回 return _excel_response(wb, file_name) + + +def update_course_priority(year: int, semester: str, priority_func: Callable[[int], float]): + """ + 根据指定学期的学时表,计算新的书院课选课权重。 + + :param year: 用于查找学时表 table, 一个可能值示例为2024 + :param semester: 用于查找学时表 table。semester的值应为'Fall'或'Spring' + :param priority_func: 一个函数,它接受一个int,表示过去学期学时无效的书院课门数,返回新学期选课优先级(0~1) + :return: None + """ + if semester not in ('Fall', 'Spring'): + raise ValueError('semester must have value of "Fall" or "Spring"!') + with transaction.atomic(): + # First, all set to 1.0 + NaturalPerson.objects.update(course_priority=1.0) + # A list of invalid record's student id. + invalid_id: List[int] = list(CourseRecord.objects.filter( + year = year, invalid = True, semester = semester + ).order_by( + 'person__id' + ).values_list( + 'person__id', flat = True + )) + # Number of invalid records + n = len(invalid_id) + # a[k] is the list of id of people who have k invalid records + a: Dict[int, List[int]] = dict() + # Length of the current continuous segment + k = 0 + for i in range(n): + k += 1 + if i == n - 1 or invalid_id[i] != invalid_id[i + 1]: + if k not in a: + a[k] = [] + a[k].append(invalid_id[i]) + k = 0 + for i in a: + # There are len(a[i]) people with i invalid records + p = priority_func(i) + NaturalPerson.objects.filter(id__in = a[i]).update(course_priority = p) diff --git a/app/management/commands/update_course_priority.py b/app/management/commands/update_course_priority.py index 0a7205a6a..f95a42cbd 100644 --- a/app/management/commands/update_course_priority.py +++ b/app/management/commands/update_course_priority.py @@ -1,10 +1,6 @@ -from typing import Dict, List - from django.core.management.base import BaseCommand -from django.db import transaction -from tqdm import trange -from app.models import CourseRecord, NaturalPerson +from app.course_utils import update_course_priority class Command(BaseCommand): # This command should be run before new semester starts @@ -14,40 +10,12 @@ def add_arguments(self, parser): parser.add_argument('year', type=int, help='year of the course records to check (required)') parser.add_argument('semester', type=str, help='semester of the course records to check. Valid values are: Fall, Spring (required)') - @transaction.atomic def handle(self, *args, **options): - # Currently, just adjust all of them to 1. - NaturalPerson.objects.update(course_priority=1.0) - # Comment out this return to enable course priority - # return - if options['semester'] not in ('Fall', 'Spring'): - print('Error: must have value of "Fall" or "Spring"!') - return - # A list of invalid record's student id. - invalid_id: List[int] = list(CourseRecord.objects.filter( - year = options['year'], invalid = True, semester = options['semester'] - ).order_by( - 'person__id' - ).values_list( - 'person__id', flat = True - )) - # Number of invalid records - n = len(invalid_id) - print(f'update_course_priority: There are {n} invalid records.') - # a[k] is the list of id of people who have k invalid records - a: Dict[int, List[int]] = dict() - # Length of the current continuous segment - k = 0 - for i in trange(n, desc = 'Processing invalid records'): - k += 1 - if i == n - 1 or invalid_id[i] != invalid_id[i + 1]: - if k not in a: - a[k] = [] - a[k].append(invalid_id[i]) - k = 0 - # Print out a summary of invalid records - for i in a: - print(f'There are {len(a[i])} people with {i} invalid records...') - p = max(0.5, 1 - 0.05 * i) - NaturalPerson.objects.filter(id__in = a[i]).update(course_priority = p) - print('Done!') + try: + # 修改这里的这个lambda,可以实现不同的权重策略 + update_course_priority(options['year'], options['semester'], + lambda x: 1 - 0.05 * x) + except Exception as e: + print('Error:', e.args) + else: + print('Success!') From f60312a6169b26072be710963626bd657ce5d6c4 Mon Sep 17 00:00:00 2001 From: Deophius Date: Mon, 20 Jan 2025 08:36:52 +0000 Subject: [PATCH 10/11] Use Counter to make code readable --- app/course_utils.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/app/course_utils.py b/app/course_utils.py index 9baee89c2..56dd6ca17 100644 --- a/app/course_utils.py +++ b/app/course_utils.py @@ -12,6 +12,7 @@ process_time: 把datetime对象转换成人类可读的时间表示 check_course_time_conflict: 检查当前选择的课是否与已选的课上课时间冲突 """ +from collections import Counter from typing import Callable, Dict from app.utils_dependency import * @@ -1504,27 +1505,22 @@ def update_course_priority(year: int, semester: str, priority_func: Callable[[in with transaction.atomic(): # First, all set to 1.0 NaturalPerson.objects.update(course_priority=1.0) - # A list of invalid record's student id. - invalid_id: List[int] = list(CourseRecord.objects.filter( + # Invalid records in the given semester + invalid_records = CourseRecord.objects.filter( year = year, invalid = True, semester = semester - ).order_by( - 'person__id' ).values_list( 'person__id', flat = True - )) - # Number of invalid records - n = len(invalid_id) + ) + # Counts the number of occurrences of a person's ID in invalid list + invalid_counter: Counter[int] = Counter(invalid_records) # a[k] is the list of id of people who have k invalid records a: Dict[int, List[int]] = dict() # Length of the current continuous segment - k = 0 - for i in range(n): - k += 1 - if i == n - 1 or invalid_id[i] != invalid_id[i + 1]: - if k not in a: - a[k] = [] - a[k].append(invalid_id[i]) - k = 0 + for person_id in invalid_counter: + cnt = invalid_counter[person_id] + if cnt not in a: + a[cnt] = [] + a[cnt].append(person_id) for i in a: # There are len(a[i]) people with i invalid records p = priority_func(i) From a85c0489eac3102b22703580790bef5f3153bee5 Mon Sep 17 00:00:00 2001 From: Deophius Date: Mon, 20 Jan 2025 10:31:15 +0000 Subject: [PATCH 11/11] Use defaultdict to simplify code --- app/course_utils.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/app/course_utils.py b/app/course_utils.py index 56dd6ca17..4a7963039 100644 --- a/app/course_utils.py +++ b/app/course_utils.py @@ -12,8 +12,8 @@ process_time: 把datetime对象转换成人类可读的时间表示 check_course_time_conflict: 检查当前选择的课是否与已选的课上课时间冲突 """ -from collections import Counter -from typing import Callable, Dict +from collections import Counter, defaultdict +from typing import Callable from app.utils_dependency import * from app.models import ( @@ -1514,12 +1514,10 @@ def update_course_priority(year: int, semester: str, priority_func: Callable[[in # Counts the number of occurrences of a person's ID in invalid list invalid_counter: Counter[int] = Counter(invalid_records) # a[k] is the list of id of people who have k invalid records - a: Dict[int, List[int]] = dict() + a = defaultdict(list) # Length of the current continuous segment for person_id in invalid_counter: cnt = invalid_counter[person_id] - if cnt not in a: - a[cnt] = [] a[cnt].append(person_id) for i in a: # There are len(a[i]) people with i invalid records