如何将此If循环放入对Python有效的字典中

时间:2017-10-29 10:42:06

标签: python if-statement switch-statement combinations boolean-logic

我正在开发一个有趣的小python项目,我不得不尝试将我的If循环调整为Dictionary,但我只是不确定如何实现这个功能,因为我需要多个条件来测试。

我有6个布尔,(bool1-bool6),显然可以是T或F,和 我需要测试这些布尔值的每种可能组合,以便我可以告诉我的程序在哪里绘制图像。

有64种可能的组合。

我们可以用3个布朗来做到这一点简单,有3种布尔可能的组合。

如果我们想象1 =真且0 =假,那么可能的组合可以表示为。

000
001
010
011
100
101
110
111

表示这个的if循环,

if (bool1==false and bool2==false and bool3==false)
      do stuff
elif (bool1==false and bool2==false and bool3==true)
     do stuff
elif (bool1==false and bool2==true and bool3==false)
     do stuff

and so on...

除非您能找到简化此过程的方法,(了解我需要检查所有可能的布尔组合),否则无需批评我的问题。我只是不确定如何从这里进步,并非常感谢一些帮助。

我写了一个64语句If Loop,我正在研究这个解决方案,虽然我和我都确定我的cpu更喜欢更快的方法。

3 个答案:

答案 0 :(得分:1)

这是使用整数位表示

的完美示例

你有六个布尔变量bool1到bool6。

想要的是有点代表如下例:

101101

最左边的位代表bool6,最右边代表bool1。 所以你得到订单bool6,bool5,bool4,...,bool1。

现在,您为状态分配一个变量,由这些布尔变量表示:

state = bool6 << 5
state = state ^ (bool5 << 4)
state = state ^ (bool4 << 3)
state = state ^ (bool3 << 2)
state = state ^ (bool2 << 1)
state = state ^ (bool1)

您找到<< here

的解释

现在发生的是,您定义了一个新的整数变量,由您的不同布尔值表示。

使用位表示

根据您的进一步do_something实施,您可以像这样定义方法参数:

cases = {
    0b000011 : "drawing parameter",
    0b001011 : "drawing parameter",
    0b111000 : "another drawing parameter",
}

其中,字典键是从000000111111

的位

另外,您可以检查每个案例是否都有一个已定义的参数:

for n in range(1<<6):
    if not n in cases:
       raise LookupError('cases do not contain index %d' % n)

因此,稍后,您可以使用这些位表示,如下所示。

for c in cases:
    if state == c: # if the checked case is equal to the state, then use the parameters
       parameters = cases[c]
       do_something(parameters)

答案 1 :(得分:0)

对于6个布尔值,有2 ^ 6个组合直接对应于从02^6-1的数字中的位。如果需要为单个函数调用定义特殊参数,可以通过使用参数列表或字典来解决此问题,然后使用每个参数调用该函数:

cases = {
    0b000000: ((arg1a, arg2y), {'key1': kwarg1, 'key2': kwarg2}),
    0b000001: ((arg1b, arg2x), {'key23': kwarg23, 'key7': kwarg7}),
    # ...
    0b111111: ((arg1a, arg2z), {'key4': kwarg4, 'key2': kwarg2}),
}

for n, (args, kwargs) in cases.items():
    print("Test case {:d} ({:#08b}):".format(n,n))
    test_fun(*args, **kwargs)

如果您不需要关键字参数,则可以轻松简化。

如果你需要做更多具体的事情,你可以在字典中使用lambdas而不是参数集:

cases = {
    0b000000: lambda: test_fun(1,2, foo='bar'),
    0b000001: lambda: test_fun(3,2, moo='bar'),
    # ...
    0b111111: lambda: test_fun(8,3, foo='bar'),
    }

for n, fun in cases.items():
    print("Test case {:d} ({:#08b}):".format(n,n))
    fun()

您还可以将这些词典转换为列表,将dict索引转换为注释:

cases = [
    # 0b000000
    ((arg1a, arg2y), {'key1': kwarg1, 'key2': kwarg2}),
    # 0b000001
    ((arg1b, arg2x), {'key23': kwarg23, 'key7': kwarg7}),
    # ...
    # 0b111111
    ((arg1a, arg2z), {'key4': kwarg4, 'key2': kwarg2}),
]

for n, (args, kwargs) in enumerate(cases):
    print("Test case {:d} ({:#08b}):".format(n,n))
    test_fun(*args, **kwargs)

在所有情况下,我都会确保在cases的定义后直接进行一致性检查,例如

# for the `cases` dictionary
for n in range(1<<6):
    if not n in cases:
        raise LookupError("dict variable cases does not contain %d" % n)

# for the `cases` list
assert(len(cases) == (1<<6))

如果您可以轻松地从索引编号中导出参数集,则可以避免定义测试用例的完整列表或字典,并且只需动态计算参数值:

for n in range(1<<6):
    param1 = 23
    if (n & (1<<0)):
        param1 = 42
    # ...
    param6 = bool(n & (1<<5))

    # ...
    test_fun(param1, ..., param6)

或者您可以将参数生成逻辑放入生成器函数中,可选择使用(可能reversed()list替换yield语句中的元组表达式。

def all_bool_tuples_from_bits(n):
    for k in range(1<<n):
        yield (bool(k&(1<<i)) for i in range(n))

print("Run test_fun with the arguments")
for args in all_bool_tuples_from_bits(6):
    test_fun(*args)

print("Run test_fun with the arguments in explicit variables")
for p0, p1, p2, p3, p4, p5 in all_bool_tuples_from_bits(6):
    test_fun(p0, p1, p2, p3, p4, p5)

print("Run test_fun with the arguments while numbering the test cases")
for n, args in enumerate(all_bool_tuples_from_bits(6)):
    print("Test case {:d} ({:#08b}):".format(n,n))
    test_fun(*args)

我希望这能为您提供一些想法。

关于CPU的使用情况,我不会担心只有64个不同的测试用例,每个测试用例都生成一个PDF文件,这个文件肯定会比迭代超过64个测试用例的CPU密集程度更高。

真正的担心是你可能忘记在那个巨大的if elif elif elif构造中列出一个案例,而不是自己注意到这一点。因此,我希望使用代码让计算机确保每个组合都经过检查。对于6个布尔参数,我会使用生成器。

答案 2 :(得分:0)

int-to-binary方法很聪明,但没有概括。有一种更简单的方法可以推广到除Boolean之外的数据类型:

import itertools
for i in itertools.product((0, 1,), repeat=3):
    ... stuff ...

这将返回(0, 0, 0), (0, 0, 1) ... (1, 1, 1)等元组。

您可以将未命名的第一个参数更改为任何可迭代 - xrange(),set,array等 - 并将repeat参数更改为所需的长度。适用于任何数据类型。