你的逻辑太复杂了,以至于我必须进行几次传递才能缩小规模并向你展示你做错了什么。
首先,正如其他人所指出的,我们将修复实际报告的错误。同时,我们将应用一个简单的原则:不要与布尔文字比较。你不会说“如果真的在下雨,我需要一把伞”。你说“如果下雨,我需要一把伞”。所以去掉多余的东西。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
后将它们转换为刚刚输出来稍微清理循环。不是邪恶的(也不是)。它们实际上简化了我们对布尔值的思考,因为我们不再检查(强调);我们只是直接与我们分配给的内容进行比较。这意味着我们也摆脱了变量,这又是一个实际上并没有告诉我们太多信息的名称。break
break
continue
not isValid
not
isValid
isValid
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
功能“匹配”什么?老实说,我无法想象。