虽然循环没有产生所需的结果

While loop not producing the required result

我正在尝试生成大学的随机时间表。

以下是我的class“部分”的定义,

class section:
    def __init__(self):
        self.id = ""
        self.course = ""
        self.section = ""
        self.instructor = ""

这就是我的数据,

1
Object Oriented Programming 
CS-3B
Dr Jen 
,
2
Object Oriented Programming 
SE-3A
Dr Bilal
,

这所有的数据都以数组形式存储在class节的对象中。 现在,所有这些课程基本上都是在不同的部分开设的。例如,课程id = 1,即面向对象编程在CS-3B.

中提供

我正在尝试根据 部分生成时间表。 例如,CS-3A 部分的时间表将包含所有CS-3A 部分提供的每门课程的讲座。此外,本节课表不应有任何重叠课程。例如,如果 CS-3B 节的第 1 门课程的讲座在第 1 个星期一举行,那么 CS-3B 节的任何其他课程的其他任何讲座都不应在第 1 个星期一举行。此外,每门课程每周有两节课。

此外,请注意我制作了一个 Slot class 具有以下定义,

class Slot:
    def __init__(self,day,slot,room):
        self.day  = day
        self.slot =  slot
        self.room = room
    
    def __repr__(self) -> str:
        return f'{self.day} {self.slot} {self.room}'

一开始为了简单起见,我保留每节课的房间=1,以后会根据需要更改。

所以,为了解决这个问题,我想出了这段代码。

t_sections = {}
for i in sections:
    if (sections[int(i.id)-1].section[:5]) not in t_sections.keys():
        t_sections[sections[int(i.id)-1].section[:5]] = [] # Make a key for new section

    for x in range(2): # Because each course must have 2 lectures
        lst = []
        day = random.randint(1, 5)
        slot = random.randint(1, 5)
        while (Slot(day, slot, 1) in t_sections[sections[int(i.id)-1].section[:5]]): # check if day + slot already exist in the sections' timetable
            day = random.randint(1, 5)
            slot = random.randint(1, 5)
        lst.append(Slot(day, slot, 1))
        t_sections[sections[int(i.id)-1].section[:5]].append([sections[int(i.id)-1].id, lst])

请不要介意[:5],我这样做只是因为有些部分被进一步划分,如 CS-1A1 和 CS-1A2,但我不想要不同的时间表这些进一步划分的部分,而是希望将他们的讲座放在他们的父部分(即 CS-1A)中,这就是我完成 [:5]

的原因

我正在做的是创建一个字典。字典的键将包含所有部分的名称,每个键的值将是一个列表,其中将包含要放置在该部分时间表中的每个讲座的更多列表。

现在,我使用了一个 while 循环来确保新生成的日期和时段随机值不存在于该部分时间表的现有列表中。也就是说,如果讲座已经在 [1, 1] 上进行,那么它不应该在同一个时间段上放置另一个讲座。

但是,我得到的结果有一些重叠的讲义,而且我似乎找不到发生这种情况的原因。 请注意,如果一些讲座重叠是可以的,如果所有的时段都被预订了,而正在追加的讲座在整个时间表中根本没有可用的时段但是,我还没有处理了这个案子。因此,据我所知,如果所有的讲座时段都已满(即 5 * 5 = 25 个时段),那么程序应该会出错,因为它永远不会退出 While 循环。

以下是我用来获取字典结果的for循环

for k, v in t_sections.items():
    print(k, ": ", v)

这是字典的一个示例结果,

CS-3B :  [['1', [4 4 1]], ['1', [1 5 1]], ['27', [4 4 1]], ['27', [3 5 1]], ['75', [4 4 1]], ['75', [3 2 1]], ['88', [3 4 1]], ['88', [5 3 1]], ['90', [5 3 1]], ['90', [5 2 1]], ['99', [2 4 1]], ['99', [1 4 1]], ['184', [1 1 1]], ['184', [5 3 1]], ['185', [5 3 1]], ['185', [5 5 1]]]
SE-3A :  [['2', [2 1 1]], ['2', [4 1 1]], ['22', [2 2 1]], ['22', [5 1 1]], ['68', [4 3 1]], ['68', [1 5 1]], ['92', [3 3 1]], ['92', [2 1 1]], ['96', [2 2 1]], ['96', [4 5 1]], ['105', [2 4 1]], ['105', [2 4 1]], ['196', [2 4 1]], ['196', [4 2 1]], ['197', [2 1 1]], ['197', [4 4 1]]]
CS-7F :  [['3', [3 4 1]], ['3', [5 5 1]], ['36', [5 5 1]], ['36', [2 3 1]]]
CS-1C :  [['4', [1 1 1]], ['4', [2 1 1]], ['97', [1 3 1]], ['97', [2 4 1]], ['111', [5 4 1]], ['111', [4 1 1]], ['139', [2 1 1]], ['139', [3 5 1]], ['140', [2 4 1]], ['140', [5 5 1]], ['141', [1 2 1]], ['141', [3 4 1]], ['142', [1 5 1]], ['142', [2 5 1]], ['143', [4 3 1]], ['143', [3 5 1]], ['144', [4 4 1]], ['144', [5 5 1]], ['145', [3 4 1]], ['145', [2 2 1]], ['146', [1 5 1]], ['146', [3 5 1]]]
CS-1D :  [['5', [2 3 1]], ['5', [1 1 1]], ['98', [2 4 1]], ['98', [5 3 1]], ['102', [5 3 1]], ['102', [3 5 1]], ['147', [5 4 1]], ['147', [2 4 1]], ['148', [5 5 1]], ['148', [2 1 1]], ['149', [5 1 1]], ['149', [3 4 1]], ['150', [1 1 1]], ['150', [2 4 1]], ['151', [2 5 1]], ['151', [4 2 1]], ['152', [2 3 1]], ['152', [1 1 1]], ['153', [4 3 1]], ['153', [2 5 1]]]
CS-7A :  [['6', [1 3 1]], ['6', [1 5 1]], ['8', [5 4 1]], ['8', [1 1 1]], ['9', [3 2 1]], ['9', [4 5 1]], ['18', [3 2 1]], ['18', [3 2 1]], ['21', [2 2 1]], ['21', [4 3 1]], ['116', [4 2 1]], ['116', [1 4 1]], ['209', [4 3 1]], ['209', [4 5 1]]]
CS-7B :  [['7', [1 5 1]], ['7', [3 4 1]], ['17', [3 4 1]], ['17', [5 5 1]], ['48', [2 1 1]], ['48', [1 1 1]], ['66', [5 5 1]], ['66', [2 2 1]], ['78', [5 3 1]], ['78', [1 4 1]]]
CS-1B :  [['10', [2 3 1]], ['10', [4 2 1]], ['93', [1 3 1]], ['93', [5 5 1]], ['122', [5 4 1]], ['122', [3 1 1]], ['131', [3 4 1]], ['131', [5 3 1]], ['132', [2 1 1]], ['132', [5 2 1]], ['133', [1 3 1]], ['133', [3 2 1]], ['134', [4 2 1]], ['134', [5 5 1]], ['135', [4 1 1]], ['135', [4 2 1]], ['136', [4 1 1]], ['136', [2 3 1]], ['137', [2 3 1]], ['137', [1 2 1]], ['138', [1 1 1]], ['138', [2 1 1]]]
CS-1A :  [['11', [1 1 1]], ['11', [1 2 1]], ['81', [4 5 1]], ['81', [5 2 1]], ['95', [3 2 1]], ['95', [5 3 1]], ['123', [2 4 1]], ['123', [4 1 1]], ['124', [4 4 1]], ['124', [5 5 1]], ['125', [1 5 1]], ['125', [5 5 1]], ['126', [2 5 1]], ['126', [1 4 1]], ['127', [1 1 1]], ['127', [3 3 1]], ['128', [1 2 1]], ['128', [1 4 1]], ['129', [2 3 1]], ['129', [1 4 1]], ['130', [3 3 1]], ['130', [3 3 1]]]

^注意,我只列出了部分结果,并没有列出所有结果。

现在,如果您清楚地查看结果,请检查 CS-1A

['11', [1 1 1]
['127', [1 1 1]
['124', [5 5 1]
['125', [5 5 1]

这些是重叠的讲座时段,不应该发生这种情况。这样的结果也可以在其他部分的时间表中找到。

任何人都可以帮我找出问题所在以及如何防止这种情况发生吗?我想要一个部分的每一节课都有独特的 Day + Slot 组合

编辑: 我将插槽 Class 更改为此,

class Slot:
    def __init__(self,day,slot,room):
        self.day  = day
        self.slot =  slot
        self.room = room
    def __eq__(self, other):
        if self.day == other.day and self.slot == other.slot:
            return True
        return False
    def __repr__(self) -> str:
        return f'{self.day} {self.slot} {self.room}'

但是现在我在这个函数上遇到这个错误 def eq,

AttributeError: 'list' object has no attribute 'day'

我认为错误是在这一行调用的,

 while (Slot(day, slot, 1) in t_sections[sections[int(i.id)-1].section[:5]]): # check if day + slot already exist in the sections' timetable

当它尝试将 Slot(day, slot, 1) 与该部分时间表中已经存在的空档进行比较时。

因为我不太确定问题出在哪里,所以我只想解释一下您的算法 在做什么。

for i in sections:
...
    sections[int(i.id)-1].section[:5]

Sections 是某种可迭代对象,returns 一个对象,其 .id 比其索引多 1(根据您的 q)。所以它的作用是:

  • 在可迭代(列表?)中查找对象
  • 计算该对象的位置 (int(i.id) - 1)
  • 检索同一个对象

不要这样做。只是做:

for section in sections: # isn't python nice?
   ...

如果你正在用这段代码做其他事情,而我的意思不对,可以解释一下。

day = random.randint(1, 5)
lot = random.randint(1, 5)
while (
        Slot(day, slot, 1) in 
        t_sections[sections[int(i.id)-1].section[:5]]
       ): 
       # check if day + slot already exist in the sections' timetable
       day = random.randint(1, 5)
       slot = random.randint(1, 5)

这样做的目的是检查您刚刚创建的特定对象是否存在于t_sections中。除非你在你的 Section 上定义了一个 .__eq__() 方法(或者从提供它的其他东西继承) python 将不知道如何将你的对象与其他对象进行比较,并且会回退到严格的身份检查 (x is y).

请注意,无需每次都查找部分,这样做会更清楚:

current_slots = section.section # or whatever

由于您的 while 循环条件可能 永远不会 为真,while 循环永远不会 运行,因此 day 的第一个(随机)值并且 slot 将被使用,因此重叠。


P.S。你建议无限循环会抛出错误。但它不会(用我知道的任何编程语言):它会永远持续下去。如果你想让它抛出一个错误,你需要跟踪迭代,如果你走得太远则手动抛出。类似于:

count = 0
while cond:
    if count > MAX_TRIES:
        raise Exception("Tried too hard")
    do_stuff()
    count += 1

我个人总是这样做:

for _ in range(MAX_TRIES):
    if not cond:
        break
    do_stuff()

我已经被多次忘记我的手动计数器变量所困扰,并且无论如何都认为它更具可读性。