生成的Lambda的非常classic 的错误(与约束无关).
考虑这个代码
ll=[]
for i in range(3):
l=lambda: print("i=", i)
ll.append(l)
ll[0]()
ll[1]()
ll[2]()
它不会像您期望的那样显示0、1、2.
它显示2、2、2.
这3个(不同的)函数都做同样的事情:它们显示i值.但如果ll[0]
、ll[1]
、ll[2]
确实是3个不同的功能,那么仍然只有一个i
.当然,当你创建ll[0]
时,i值是0
.但ll[0]
作业(job)是为了显示i
,而不是显示i
曾经在创建ll[0]
时所具有的值.
有多种方法可以强制判断i
它们能互相
ll=[]
for i in range(3):
(lambda i: ll.append(lambda: print("i=", i)))(i)
ll[0]()
ll[1]()
ll[2]()
此时显示为0、1、2.
因为ll[0]
就是显示i
.但这次i不是for循环的(唯一)计数器.i
是所调用的拉姆达的参数.而且它们的数量与调用该Lambda(lambda i:...
函数,而不是在其中创建的函数)的数量一样多.
同一代码的更清晰(但更长)版本将是
ll=[]
def createAndAddLambdaToLL(x):
l=lambda: print("x=", x)
ll.append(l)
for i in range(3):
createAndAddLambdaToLL(i)
ll[0]()
ll[1]()
ll[2]()
createAndAddLambdaToLL
是我之前代码的外部Lambda.
请注意,我还重命名了参数x
,以明确打印的不是i
(i
,在ll[?]()
次调用时,所有这些都是2),而是打印的是x
.还有3个不同的x
,当调用createAndAddLambdaToLL
时创建.
编辑:我添加了Bakuriu的 comments ;另一种方法确实是添加可选参数:
ll=[]
for i in range(3):
l=lambda i=i: print("i=", i)
ll.append(l)
ll[0]()
ll[1]()
ll[2]()
确实打印0,1,2
因为这里有2种i
种.打印的i
不是for
循环计数器.它是局部参数i
(ll[0](12)
打印12).这样的i
有3个(1个,每个ll[...]
个本地).
默认值是创建函数时计数器i
的值.
因此,当谈到理解为什么它是必要的以及为什么它有效时,Bakuriu的解决方案和我的一样复杂.但写作要简单得多,而且几乎自然.
回到你的问题
from constraint import *
n = 8
problem = Problem()
problem.addVariables(range(n),range(n))
def addConstraintDiag(i,j):
problem.addConstraint(lambda a,b: abs(a-b)!=abs(i-j), (i,j))
for i in range(n):
for j in range(i):
problem.addConstraint(lambda a,b:a!=b,(i,j))
addConstraintDiag(i,j)
print(problem.getSolutions())
请注意,第一个约束(不共享行)不是问题,因为lambda a,b:a!=b
不依赖于i
和j
(事实上,它是同一函数的28倍.您可以在循环外为所有人创建一次它,并将其作为约束添加28次.但重点是,这并不重要.该功能不需要其i
和j
是全部28个组合,因为它甚至不使用i
和j
.约束本身可以,但Lambda则不然.
不过,为了安全起见,您可以在函数addConstraints
中添加2个约束,而不必认真思考是否需要对i
和j
进行部分判断.
编辑:
或者,使用Bakuriu的命令:
from constraint import *
n = 8
problem = Problem()
problem.addVariables(range(n),range(n))
for i in range(n):
for j in range(i):
problem.addConstraint(lambda a,b:a!=b,(i,j))
problem.addConstraint(lambda a,b,i=i,j=j: abs(a-b)!=abs(i-j), (i,j))
print(problem.getSolutions())