你的逻辑太复杂了,以至于我必须进行几次传递才能缩小规模并向你展示你做错了什么。
首先,正如其他人所指出的,我们将修复实际报告的错误。同时,我们将应用一个简单的原则:不要与布尔文字比较。你不会说“如果真的在下雨,我需要一把伞”。你说“如果下雨,我需要一把伞”。所以去掉多余的东西。if isValid比更清楚if isValid == True,因为它准确地突出了isValid应该是什么意思。我还将取出调试跟踪(print显然只是为了检查代码是否在做正确的事情的语句;首先简化代码,然后检查更少)。
def match(pList):
b = []
z = len(pList)-1
for x in range(z):
b.append([pList[x][0],0])
for x in range(z):
isValid = False
q = p = 0
while not isValid:
q = random.randint(0, z)
if q > z:
isValid = False
elif q < 0:
isValid = False
elif pList[q][1]:
isValid = False
else:
isValid = True
isMatch = False
while not isMatch:
if not pList[q][1]:
isValid = False
while not isValid:
p = random.randint(0,z)
if p > z:
isValid = False
elif p < 0:
isValid = False
elif pList[p][2]:
isValid = False
else:
if q == p:
isValid = False
else:
isValid = True
b[q][1] = pList[p][0]
isMatch = True
return b
接下来,我们将简化我们的条件逻辑。首先,返回的结果random.randint(0, z) 不能是< 0也不> z,永远,无论如何。这是功能的一部分。因此,编写代码来处理这些情况是没有意义的,实际上这样做是错误的。编写代码来处理某些事情意味着它实际上可能会发生。这对阅读代码的人来说是一种分心,而且是一个谎言。它在重要的事情(调用random.randint和检查pList值)之间放置了额外的空间。
我们还将简化 if/else 对,它们只是相应地设置另一个布尔值。出于同样的原因,你不会写
if x == 1:
y == 1
elif x == 2:
y == 2
# ... etc. ad infinitum for every possible integer value of x
你也不应该对布尔值做同样的事情。最后,我们可以而且应该使用逻辑and和or来连接布尔条件。
def match(pList):
b = []
z = len(pList)-1
for x in range(z):
b.append([pList[x][0],0])
for x in range(z):
isValid = False
q = p = 0
while not isValid:
q = random.randint(0, z)
isValid = not pList[q][1]
isMatch = False
while not isMatch:
if not pList[q][1]:
isValid = False
while not isValid:
p = random.randint(0,z)
isValid = not pList[p][2] and (q != p)
b[q][1] = pList[p][0]
isMatch = True
return b
我的下一步将是修复列表索引。索引到列表中通常不是你真正想要的,实际上它在这里引入了一个错误。很明显,您想要遍历 ; 的每一“行” pList。但是range(z)给你从0到z-1包含的数字,所以len(pList)在计算中减去 1 是不正确的z。例如,如果pList有 5 个元素,您将计算z = 4并产生range(z) = [0, 1, 2, 3]。您将永远无法访问pList[4],并且b只有 4 个元素。
z从根本上说,您正在用 做两件事。一个是使循环运行的次数与 中的“行”一样多pList,并且(在第一个循环中)对每个“行”执行一些操作。去做这个
这很重要:range不是魔术,它与 for-loops 没有特殊联系。它只是一个产生数字列表的函数。在 Python 中,for循环直接为您提供元素。所有这些索引废话就是 - 废话,最好留给能力较弱的语言。如果你想对列表的每个元素做一些事情,那么通过编写循环遍历列表的每个元素的代码,对列表的每个元素做一些事情。直接地。不要超过一些单独的索引列表,然后您可以使用这些索引将其索引回原始索引。这会让事情变得复杂。
您要做的第二件事z是生成一个可能的索引的随机数,以便您可以索引pList以获得随机行。换句话说,您只想选择一个随机行。所以只需随机选择一行。该random模块直接提供此功能:该函数被调用random.choice,它的功能与听起来完全一样。
这里有一个小问题:原始代码比较p == q,即比较两个随机选择的列表索引是否相等。如果我们不再编制索引,那么我们就没有可比较的索引。要解决这个问题,我们需要了解最初的目的是什么:再次检查新选择的行是否实际上是旧选择的行。同样,我们通过直接检查来简化:我们选择新行而不是新索引,然后查看它是否is是旧行。
我们还有一个问题,我们需要从中选择一个对应的行,b该行对应于pList我们之前识别为 的行q。为了解决这个问题,我们可以在选择b行的同时选择pList行。这有点棘手:我的方法是制作成对的行列表 - 在每一对中,会有一行 from b,然后是一行 from pList。这不需要任何复杂的东西——实际上有一个内置函数可以完全按照我们的意愿拼接b在一起pList:它被称为zip. 无论如何,从该行对列表中选择了一个行对,我们只需将这两行解压缩为两个变量 - 使用q, p = ...事实证明,您首先错误地使用了语法。这就是它的用途。
p通过这些更改,我们实际上可以q完全摆脱z. 这很好,因为根本不清楚这些名字应该是什么意思。
def match(pList):
b = []
for row in pList:
b.append([row[0], 0])
for row in pList:
isValid = False
while not isValid:
first_row, b_row = random.choice(zip(pList, b))
isValid = not first_row[1]
isMatch = False
while not isMatch:
if not first_row[1]:
isValid = False
while not isValid:
second_row = random.choice(pList)
isValid = not second_row[2] and (first_row is not second_row)
b_row[1] = second_row[0]
isMatch = True
return b
是时候进行一些更合乎逻辑的清理了。在第一个 while 循环中,我们将继续循环直到isValid变为 true。也就是说,直到not first_row[1]成为真的。在第二个 while 循环中,first_row永远不会改变,因此,由于not first_row[1]循环开始时为真,因此它将始终保持为真。因此,完全没有必要进行 if-check。
一旦它消失了,我们发现第二个while循环实际上也完全没用:它会循环while not isMatch,即直到 isMatch。是什么isMatch?好吧,在我们开始循环之前,它是False,在循环结束时,它是True。总是。所以我们知道这段代码只会运行一次。我们进入循环,走到最后,设置isMatch为真,然后退出,因为isMatch刚刚设置为真,是真。只运行一次的代码不需要循环;这只是代码。
我将在这里做的另一件事是通过在我们完成while isValid后将它们转换为刚刚输出来稍微清理循环。不是邪恶的(也不是)。它们实际上简化了我们对布尔值的思考,因为我们不再检查(强调);我们只是直接与我们分配给的内容进行比较。这意味着我们也摆脱了变量,这又是一个实际上并没有告诉我们太多信息的名称。breakbreakcontinuenot isValidnotisValidisValid
def match(pList):
b = []
for row in pList:
b.append([row[0], 0])
for row in pList:
while True:
first_row, b_row = random.choice(zip(pList, b))
if not first_row[1]:
break
while True:
second_row = random.choice(pList)
if not second_row[2] and (first_row is not second_row):
break
b_row[1] = second_row[0]
return b
最后一件事:我们可以b更干净地构建。通过附加元素来建立一个列表是一个傻瓜游戏。不要告诉 Python 如何构建列表。它知道怎么做。相反,要求一个符合您的规范的列表,并带有列表理解。这比解释更简单(如果你需要解释,请咨询谷歌),所以我会继续给你一个版本:
def match(pList):
b = [[row[0], 0] for row in pList]
for row in pList:
while True:
first_row, b_row = random.choice(zip(pList, b))
if not first_row[1]:
break
while True:
second_row = random.choice(pList)
if not second_row[2] and (first_row is not second_row):
break
b_row[1] = second_row[0]
return b
从这里开始,如果不了解您实际在做什么,就很难纠正或改进任何事情。经过所有这些工作,我仍然不知道!
您设置它的方式,您选择一个随机行,与行数一样多 - 但您仍然可以选择重复项。那是你真正想要的吗?还是您想以随机顺序选择每一行一次?无论如何,以随机顺序执行它有什么意义?
选择第一行后,您随机选择第二行进行匹配。你真的想要每第一行一个随机行吗?还是您想尝试所有可能的行对?
到底这些数据是什么?输出b数据代表什么?一开始到底是什么pList,为什么叫它pList?您与此match功能“匹配”什么?老实说,我无法想象。