组合条件语句排列的最佳方法

时间:2019-03-29 17:33:31

标签: python if-statement conditional combinations

因此,基于4个条件变量,我要执行一系列操作-假设x,y,z和t。这些变量中的每一个都有可能的True或False值。因此,总共有16种可能的排列。而且我需要为每个排列执行不同的操作。

执行此操作而不是进行庞大的if-else构造的最佳方法是什么。

让我们看一个简化的例子。如果我尝试将所有不同的排列包含到一个大型的if-else结构中,这就是我的代码的样子。

if (x == True):
    if (y == True):
        if (z == True):
            if (t == True):
                print ("Case 1")
            else:
                print ("Case 2")
        else:
            if (t == True):
                print ("Case 3")
            else:
                print ("Case 4")
    else:
        if (z == True):
            if (t == True):
                print ("Case 5")
            else:
                print ("Case 6")
        else:
            if (t == True):
                print ("Case 7")
            else:
                print ("Case 8")
else:
    if (y == True):
        if (z == True):
            if (t == True):
                print ("Case 9")
            else:
                print ("Case 10")
        else:
            if (t == True):
                print ("Case 11")
            else:
                print ("Case 12")
    else:
        if (z == True):
            if (t == True):
                print ("Case 13")
            else:
                print ("Case 14")
        else:
            if (t == True):
                print ("Case 15")
            else:
                print ("Case 16")

有什么方法可以简化这个过程吗?显然,我针对每种情况的目标都比仅打印“案例1”更为复杂。

9 个答案:

答案 0 :(得分:5)

您可以使用案例映射到结果:

zip = zipWith' (,)

如果您想针对每种情况执行其他操作/不同操作,则可以向该地图添加功能。

indices = pd.Series(ds.index, index=ds['_id']).drop_duplicates()


   def get_recommendations(id, cosine_sim=cosine_sim):


    idx = indices[id]


    sim_scores = list(enumerate(cosine_sim[idx]))


    sim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True)


    sim_scores = sim_scores[1:11]
    sc=[]
    for count,ele in sim_scores: 
       sc.append(ele)




    movie_indices = [i[0] for i in sim_scores]
    ff = pd.DataFrame(columns=['A','B','C'])
    ff['A']=ds['_id'].iloc[movie_indices]
    ff['B']=ds['title'].iloc[movie_indices]
    ff['C']=sc


   return ff

get_recommendations('4fd2b43e8eb7c8105d8a67e8')

您还可以使用一种掩蔽解决方案来缩短代码,或者如果您要写出的案例过多,但是对于较小的案例集,此显式表示将更清晰且易于维护。

答案 1 :(得分:1)

您可以将所有值推入一个元组并使用16个元组比较。

if   (x, y, z, t) == (True,  True,  True,  True):  print("Case 1")
elif (x, y, z, t) == (True,  True,  True,  False): print("Case 2")
elif (x, y, z, t) == (True,  True,  False, True):  print("Case 3")
elif (x, y, z, t) == (True,  True,  False, False): print("Case 4")
elif (x, y, z, t) == (True,  False, True,  True):  print("Case 5")
elif (x, y, z, t) == (True,  False, True,  False): print("Case 6")
elif (x, y, z, t) == (True,  False, False, True):  print("Case 7")
elif (x, y, z, t) == (True,  False, False, False): print("Case 8")
elif (x, y, z, t) == (False, True,  True,  True):  print("Case 9")
elif (x, y, z, t) == (False, True,  True,  False): print("Case 10")
elif (x, y, z, t) == (False, True,  False, True):  print("Case 11")
elif (x, y, z, t) == (False, True,  False, False): print("Case 12")
elif (x, y, z, t) == (False, False, True,  True):  print("Case 13")
elif (x, y, z, t) == (False, False, True,  False): print("Case 14")
elif (x, y, z, t) == (False, False, False, True):  print("Case 15")
elif (x, y, z, t) == (False, False, False, False): print("Case 16")

可以将其转换为dict查找或使用巧妙的二进制打包技巧,但是这里的优点是(a)简单明了; (b)不需要lambda或功能; (c)您可以将任何东西放入这16个案件中。

答案 2 :(得分:1)

您可以直接通过对布尔值进行二进制操作来获得案例编号:

case = (x^1) << 3 | (y^1) << 2 | (z^1) << 1 | (t^1) + 1
print(f'Case {case}')

如果您查看John Kugelman's answer,您会发现x, y, z, t只是案件编号的“位”(其中True=0False=1)……因此,我构造int设置这些位(然后添加1,因为您是从1开始计数的。)

如果编号是任意的,则可以简化为x << 3 | y << 2 | z << 1 | t,然后从那里获取。

这很容易扩展为大量的布尔变量。

然后根据案例编号进行操作,建议您创建一个包含case作为键,函数或数据或值的字典。像这样:

case_functions = {1: func_1, 2: func_2, ...}
res = case_functions(case)(some argument)

答案 3 :(得分:1)

这是一种灵活的解决方案,可提供可伸缩性和一定程度的简单性。

首先,您需要创建将针对每个输出运行的方法。这些是print("case X")语句的“复杂”版本

#Define your method outcomes here...
#Note that this follows a binary layout starting with 
# a + b + c + d = false
def action1():      #binary 0 (a'b'c'd')
    print("case 1")
def action2():      #binary 1 (a'b'c'd)
    print("case 2")
def action3():      #binary 2 (a'b'cd')
   print("case 3")
def action4():      #binary 3 (a'b'cd)
    print("case 4")
def action5():      #binary 4 (a'bc'd')
    print("case 5") #etc...
def action6():
    print("case 6")
def action7():
    print("case 7")
def action8():
    print("case 8")
def action9():
    print("case 9")
def action10():
    print("case 10")
def action11():
    print("case 11")
def action12():
    print("case 12")
def action13():
    print("case 13")
def action14():
    print("case 14")
def action15():
    print("case 15")
def action16():
    print("case 16")
def actionDefault():
    print("Error!")

然后,稍后可以通过创建方法名称列表,然后创建一个在调用时引用该方法列表的方法来轻松引用这些特定的操作方法。

import itertools #Generates all permutations
import sys       #Allows us to get the current module

#Returns the index of the actionList we should execute
def evaluateActionIndex(varList): 
    allcombinations = itertools.product([False, True], repeat=len(varList))
    i = 0
    for subset in allcombinations: #for each of the possible combinations...
        if list(subset) == varList: #Check to see if we want to execute this index.
            return i
        i = i + 1                  #Increment the target index
    return -1                      #Execute default method (-1 index)

def performAction(index):
    actionList = [action1.__name__, action2.__name__, action3.__name__, action4.__name__, 
                  action5.__name__, action6.__name__, action7.__name__, action8.__name__,
                  action9.__name__, action10.__name__, action11.__name__, action12.__name__,
                  action13.__name__, action14.__name__, action15.__name__, action16.__name__,
                  actionDefault.__name__]
    method = getattr(sys.modules[__name__], actionList[index])  #Get method by name
    method()                                                    #Execute Method

我们可以使用以下方法执行一些操作:

#Mock up some control inputs
a = False
b = True
c = False
d = False
controlVariables = [a, b, c, d] #All Your Control Variables

#Execute control sequence
performAction(evaluateActionIndex(controlVariables))

我已经对此进行了测试,并且效果很好。您可以根据需要在controlVariables列表中添加任意数量的控制变量。

答案 4 :(得分:1)

那太好了。一点!很干净。

我一直在寻找解决方案。

这是JavaScript版本:

//assuming you have your variables in an array
let q = evaluatedQuery = ["wd:Q82955", "wd:Q212238", "", "wd:Q116"]

//lenght of the binary string
let possibleCases = evaluatedQuery.length
let binaryCase = ""


for (let i = 0; i < possibleCases; i++) {

    // this "!!" makes a value truthy or falsy,
    // and converts that to an integer "!!q[i] ^ 0"

    binaryCase = `${binaryCase}${!!q[i] ^ 0}`

}

//this finds out which of (q*q = 16) cases its gonna be
let parsedBinaryCase = parseInt(binaryCase, 2) + 1

//this converts it to an array for easy handling
let binaryCaseArr = binaryCase.split("")

//this filers out falsy values by taking falsy values index
let boundQueryElements = evaluatedQuery.filter((el, i) => {
    return !binaryCaseArr[i] != !!el ^ 0 
})

console.log(binaryCase) //output: 1101
console.log(parsedBinaryCase) //output: 14
console.log(boundQueryElements) //output: ['wd:Q82955','wd:Q212238','wd:Q116']

//and this is a clean way to handle those 16 cases
//in this example it would go to case 14
switch (parsedBinaryCase) {
    case 1:
        break
    case 2:
        break
    case 3:
        break
    case 4:
        break
    case 5:
        break
    case 6:
        break
    case 7:
        break
    case 8:
        break
    case 9:
        break
    case 10:
        break
    case 11:
        break
    case 12:
        break
    case 13:
        break
    case 14:
     // for (let el in boundQueryElements) {
     // }
        break
    case 15:
        break
    case 16:
        break
    default:
}

它就像“拉平”了树形结构。

答案 5 :(得分:0)

只需使用TrueFalse值的二元性:

x = True
y = True
z = True
t = True
total = bin(x + 2 * y + 4 * z + 8 * t)
print(total)
print(int(total, 2))

输出:

  

0b1111

     

15

x = False
y = True
z = False
t = True
total = bin(x + 2 * y + 4 * z + 8 * t)
print(total)
print(int(total, 2))

收益:

  

0b1010

     

10

现在,您可以轻松地使用int(total, 2)值来确定要处理的情况

因此您可以将代码转换为单级缩进:

case = int(total, 2)
if case == 0:
    print('case 0')
elif case == 1:
    print('case 1')
elif case == 2:
    print('case 2')
...

答案 6 :(得分:0)

在很多情况下,我通常更喜欢编写帮助程序功能,以使代码更易于维护,例如:

def compare(xyzt, binaryval):
    boolval = tuple(digit == '1' for digit in binaryval)
    return all(a == b for a, b in zip(xyzt, boolval))

那么您的if语句可以写为:

xyzt = (x, y, z, t)
if   compare(xyzt, '1111'): ...
elif compare(xyzt, '1110'): ...
elif compare(xyzt, '1100'): ...
etc.

这使验证您已考虑所有情况的工作变得更加容易。

答案 7 :(得分:0)

我认为这是处理程序注册表的好地方。这不会给您最短的代码,但是我认为它为您提供了更易于阅读和维护的代码,这是“更简单”的一种解释。我会做这样的事情:

registry.py

handlers = dict()
def register(x, y, z, t):
    if (x, y, z, t) in handlers:
        raise ValueError("Handler already registered for {}/{}/{}/{}".format(
                x, y, z, t))
    def insert(f):
        handlers[(x, y, z, t)] = f
    return insert

def handle(x, y, z, t):
    if (x, y, z, t) not in handlers:
        raise KeyError("No handler registered for {}/{}/{}/{}".format(
                x, y, z, t))
    return handlers[(x, y, z, t)]()

handlers.py

from delegation import register, handle

@register(x=True, y=True, z=False, t=True)
def some_descriptive_name():
    print("hi!")

@register(x=True, y=False, z=True, t=False)
def another_good_name():
    print("Yes hello.")

# etc.

main.py

from handlers import handle

x, y, z, t = True, False, False, True
handle(x, y, z, t)

这使您可以确切地看到每个处理程序将被激活的条件。将处理程序分成各自的功能也可以进行更清洁的测试。我添加了一项检查,以确保您不尝试多次处理相同的条件,并提供一条错误消息,说明是否未处理一组条件。添加检查以确保同时处理所有所有案例很容易。

如果您的操作需要使用变量(除了四个条件之外),您也可以这样做;只需更改handle的签名和返回值,就像这样:

def handle(x, y, z, t, *args, **kwargs):
    ...
    return handlers[(x, y, z, t)](*args, **kwargs)

,当然,还要向处理程序添加参数。

答案 8 :(得分:0)

扩展@Reedinationer的答案:

# your functions
def f0(): print('case 1')
def f1(): print('case 2')
def f2(): print('case 3')
#.
#.
def f15(): print('case 16')

list_of_functions = [f0, f1, f2] # assuming there are 16 functions in total

x = False
y = False
z = False
t = False
total = bin(x + 2 * y + 4 * z + 8 * t)
index = int(total, 2)

list_of_functions[index]() # will print('case 1')

在python 2.7和3.7上测试