避免重复 if 语句

时间:2021-01-09 11:31:46

标签: python algorithm if-statement repeat

我为此任务准备了函数和排序数据: (实际上是 AoC 第 4 天,但要快速解释清楚) 我已经将数据排序到这个“结构”

byr:1991
eyr:2022
hcl:#341e13
iyr:2016
pid:729933757
hgt:167cm
ecl:gry

hcl:231d64
cid:124
ecl:gmt
eyr:2039
hgt:189in
pid:#9c3ea1

ecl:#1f58f9
pid:#758e59
iyr:2022
hcl:z
byr:2016
hgt:68
eyr:1933

[等等+250个包(包我的意思是一组byr,ecl,eyr......用新行分隔)。]

并准备好这段代码:

def check_fields(list):
    comparison_list = ['byr', 'iyr', 'eyr',
                       'hgt', 'hcl', 'ecl',
                       'pid']
    statement = True
    for i in comparison_list:
        statement = statement and (i in list)
    return statement


def check_byr_iyr_eyr(line):
    prefix,value = line.split(':')
    cases = {'byr':{'min':1920, 'max':2002},
             'iyr':{'min':2010, 'max':2020},
             'eyr':{'min':2020, 'max':2030} }
    return cases[prefix]['min'] <= int(value) <= cases[prefix]['max']


def check_hgt(line):
    unit = line[len(line)-2] + line[len(line)-1]
    value = line[line.index(':')+1: -2]
    cases = {'cm':{'min':150, 'max':193},
             'in':{'min':59, 'max':76}}
    return cases[unit]['min'] <= int(value) <= cases[unit]['max']


def check_hcl(line):
    statement = True
    if line[line.index(':')+1] != '#' or len(line[line.index(':')+2:]) != 6:
        return False
    else:
        string = line[line.index('#')+1:]
        for i in string:
            statement = statement and (97 <= ord(i) <= 102 or 48 <= ord(i) <= 57)
        return statement


def check_ecl(line):
    comparison_list = ['amb', 'blu', 'brn',
                       'gry', 'grn', 'hzl',
                       'oth' ]
    if line[line.index(':') + 1:] in comparison_list:
        return True
    return False


def check_pid(line):
    if len(line[line.index(':')+1:]) != 9:
        return False
    try:
        int(line[line.index(':')+1:])
        return True
    except:
        return False


line_list = []
valid_passports = 0
with open('results.txt', 'r') as f:
    for line in f:
        if line != '\n':
            ''' add line to line_list'''
            pass
        else:
            '''
            check lines from line_list
            using above declared functions
            if every line is ok:
                valid_passports +=1
            '''

我必须检查每个包是否包含除 cid 之外的每个键,然后检查每个键的每个值是否正确。

byr (Birth Year) - four digits; at least 1920 and at most 2002.
iyr (Issue Year) - four digits; at least 2010 and at most 2020.
eyr (Expiration Year) - four digits; at least 2020 and at most 2030.
hgt (Height) - a number followed by either cm or in:
If cm, the number must be at least 150 and at most 193.
If in, the number must be at least 59 and at most 76.
hcl (Hair Color) - a # followed by exactly six characters 0-9 or a-f.
ecl (Eye Color) - exactly one of: amb blu brn gry grn hzl oth.
pid (Passport ID) - a nine-digit number, including leading zeroes.
cid (Country ID) - ignored, missing or not. 

(上述规则由较早声明的函数确保)
问题/问题是如何在检查添加到行列表的每一行时避免重复 if 语句(它指的是带有“伪代码”的多​​行注释部分)? - 我的意思是我可以这样做

if line[0:3] == "byr":
    check_byr(line)
# and so on, many if statement checking the first 3 letters to adjust proper function to use

但这似乎不是适当而优雅的解决方案,也许您可​​以给我提示如何处理它,或者给出另一个想法以我没有使用的不同方式解决该问题。 请帮忙,谢谢。

5 个答案:

答案 0 :(得分:2)

你不能有从前缀到目标函数的映射吗?

类似的东西

    _textChange(text) {
        this.setState({
            textValue: text,
        })
     }

答案 1 :(得分:1)

@viGor207,这是另一种方法:(第 2 部分示例):

import re

passports = [
    dict(
        line.split(':')
        for line
        in pas.split()
    )
    for pas
    in open('input').read().split('\n\n')
]

required = {'byr', 'iyr', 'eyr', 'hgt', 'hcl', 'ecl', 'pid'}


def valid(pas):
    return bool(
        1920 <= int(pas['byr']) <= 2002 and
        2010 <= int(pas['iyr']) <= 2020 <= int(pas['eyr']) <= 2030 and
        re.fullmatch(r'[0-9]{2,3}(cm|in)', pas['hgt']) and
        (
            (pas['hgt'][-2:] == 'cm' and 150 <= int(pas['hgt'][:-2]) <= 193) or
            (pas['hgt'][-2:] == 'in' and 59 <= int(pas['hgt'][:-2]) <= 79)
        ) and
        re.fullmatch(r'#[0-9a-f]{6}', pas['hcl']) and
        pas['ecl'] in {'amb', 'blu', 'brn', 'gry', 'grn', 'hzl', 'oth'} and
        re.fullmatch(r'[0-9]{9}', pas['pid'])
    )


print(
    sum(
        all(r in pas for r in required) and valid(pas)
        for pas
        in passports
    )
)

答案 2 :(得分:1)

为了使它完整,这是第一部分:

passports = [
    dict(
        line.split(':')
        for line
        in pas.split()
    )
    for pas
    in open('input').read().split('\n\n')
]

required = {'byr', 'iyr', 'eyr', 'hgt', 'hcl', 'ecl', 'pid'}

print(
    sum(
        all(r in pas for r in required)
        for pas in passports
    )
)

答案 3 :(得分:1)

任务说明:

<块引用>

每本护照都表示为一系列键值对 以空格或换行符分隔。护照用空格隔开 线。

sequence 对的 key:value 在 Python 中使用 listdicts,但可以使用您的方法。

您可以使用将字段名称映射到检查该字段行 field_to_checker 的函数的字典。我将您的示例解析输入作为解析行的列表,然后添加了一个仅返回 True 的 cid 检查器,并创建了以下代码片段:

def check_cid(line):
    return True

field_to_checker = {
  'byr': check_byr_iyr_eyr,
  'cid': check_cid,
  'ecl': check_ecl,
  'eyr': check_byr_iyr_eyr,
  'hcl': check_hcl,
  'hgt': check_hgt,
  'iyr': check_byr_iyr_eyr,
  'pid': check_pid,
  }

line_data = """byr:1991
eyr:2022
hcl:#341e13
iyr:2016
pid:729933757
hgt:167cm
ecl:gry

hcl:231d64
cid:124
ecl:gmt
eyr:2039
hgt:189in
pid:#9c3ea1

ecl:#1f58f9
pid:#758e59
iyr:2022
hcl:z
byr:2016
hgt:68
eyr:1933""".split('\n')

valid_passports = 0
ok_passport = True  # Accumulating over all fields of one passport
for line in line_data + ['\n']:  # Add empty line to force processing last passport
    line = line.rstrip()
    if line:    # Not blank line
        if ok_passport:  # One False value in a passport will prevail
            key = line[:3]
            ok_passport = (key in field_to_checker 
                           and field_to_checker[key](line))
    else:  # Blank line, end of passport record
        if ok_passport:
            valid_passports += 1
        ok_passports = True

for line in line_data + ['\n'] 循环中,valid_passports 的计数仅在护照记录结束时出现空行时更新。最后一本护照后面需要有一个空行才能正确计数,因此在 line_data 的末尾添加了一个额外的空行。

以上内容未经测试,但应该会为您提供有关如何扩展已开始使用的内容的提示。

答案 4 :(得分:0)

我建议尽早将字典值放在变量中,以使逻辑更易于编写和读取。

这应该允许您制作可识别的单行条件:

data = \
"""byr:1991
eyr:2022
hcl:#341e13
iyr:2016
pid:729933757
hgt:167cm
ecl:gry

hcl:231d64
cid:124
ecl:gmt
eyr:2039
hgt:189in
pid:#9c3ea1

ecl:#1f58f9
pid:#758e59
iyr:2022
hcl:z
byr:2016
hgt:68
eyr:1933"""

...

# iterator to get packages
def getPackages(d):
    package = dict()    
    for line in d:
        if line:
            field,value = line.split(":",1)
            package[field]=value
        else:
            yield package.copy()
            package.clear()
    if package: yield package

fields  = ['byr', 'iyr', 'eyr', 'hgt', 'hcl', 'ecl', 'pid']
for package in getPackages(data.split("\n")):
    values = [package.get(f,"") for f in fields]
    byr, iyr, eyr, hgt, hcl, ecl, pid = values

    isValid = "" not in values[:-1] \
        and   int(byr) in range(1920,2001+1) \
        and   int(iyr) in range(2010,2020+1) \
        and   int(eyr) in range(2020,2030+1) \
        and   int(hgt[:-2]) in {"cm":range(150,193+1),"in":range(59,76+1)}.get(hgt[-2:],[]) \
        and   hcl.startswith("#") and len(hcl)==7 \
        and   all(97 <= ord(i) <= 102 or 48 <= ord(i) <= 57 for i in hcl[1:]) \
        and   ecl in {'amb', 'blu', 'brn', 'gry', 'grn', 'hzl', 'oth' } \
        and   (pid == "" or pid.isdigit() and len(pid)==9)

    print(pid,isValid)

"""        
    729933757 True
    #9c3ea1 False
    #758e59 False
"""
相关问题