Advent of Code第4天护照验证任务:如何避免重复使用if语句调用字段验证函数
解决Advent of Code第4天的护照验证代码优化问题
嗨,针对你遇到的「不想用一堆if判断来调用不同字段验证函数」的问题,最优雅的解决方案是用字典映射字段到对应的验证函数,这样既简洁又易于维护。先理清楚你的需求和现有代码,再给出具体的实现:
需求回顾
你需要完成两步护照验证:
- 检查数据包是否包含除
cid外的所有必填字段(byr、iyr、eyr、hgt、hcl、ecl、pid) - 验证每个字段的取值符合规则(你已经编写了对应的验证函数)
现有代码
你已经实现了各个字段的验证逻辑,如下:
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
核心优化:字段-验证函数映射字典
我们可以创建一个字典,将每个必填字段直接关联到对应的验证函数,这样无需写一堆if判断,直接通过字段名查找函数即可。具体实现如下:
1. 创建映射字典
首先定义一个字典,把每个字段和它的验证函数绑定:
field_validators = { 'byr': check_byr_iyr_eyr, 'iyr': check_byr_iyr_eyr, 'eyr': check_byr_iyr_eyr, 'hgt': check_hgt, 'hcl': check_hcl, 'ecl': check_ecl, 'pid': check_pid }
这里byr、iyr、eyr共享同一个验证函数,直接映射过去就好。
2. 修改数据包处理逻辑
接下来修改读取文件和验证的代码,利用这个映射字典来简化验证流程:
line_list = [] valid_passports = 0 with open('results.txt', 'r') as f: for line in f: stripped_line = line.strip() if stripped_line: # 将当前行的字段拆分后添加到当前数据包列表 line_list.extend(stripped_line.split()) else: # 处理当前数据包 valid_passports += process_passport(line_list) # 重置列表,准备下一个数据包 line_list = [] # 处理文件末尾没有换行的最后一个数据包 if line_list: valid_passports += process_passport(line_list) print(f"有效护照数量:{valid_passports}")
3. 封装验证逻辑为函数(可选但更清晰)
为了代码更模块化,可以把单个数据包的验证逻辑封装成一个函数:
def process_passport(fields): # 第一步:检查必填字段是否齐全 field_names = [item.split(':')[0] for item in fields] required_fields = {'byr', 'iyr', 'eyr', 'hgt', 'hcl', 'ecl', 'pid'} # 简化check_fields的实现,用集合运算更高效 if not required_fields.issubset(field_names): return 0 # 第二步:验证每个字段的取值 for field_line in fields: field_name, _ = field_line.split(':', 1) # 跳过cid字段 if field_name == 'cid': continue # 通过映射字典获取验证函数并执行 validator = field_validators[field_name] if not validator(field_line): return 0 return 1
额外优化建议
- 简化
check_fields:用集合的issubset方法比循环判断更简洁高效,就像上面process_passport里的写法。 - 优化
check_hcl:用正则表达式可以简化字符验证逻辑,比如:import re def check_hcl(line): _, value = line.split(':') return re.fullmatch(r'#[0-9a-f]{6}', value) is not None - 健壮性提升:在
check_hgt里可以先判断单位是否合法(比如是否是cm或in),避免出现KeyError。
内容的提问来源于stack exchange,提问作者viGor027
相关产品推荐
相关产品推荐

