【发布时间】:2018-06-29 22:48:15
【问题描述】:
我有一个看起来像这样的“非结构化”列表:
info = [
'Joe Schmoe',
'W / M / 64',
'Richard Johnson',
'OFFICER',
'W / M /48',
'Adrian Stevens',
'? / ? / 27'
]
非结构化,因为列表由以下集合组成:
- (姓名、军官身份、人口统计信息)三胞胎,或
- (姓名、人口统计信息)对。
在后一种情况下,Officer=False,在前一种情况下,Officer=True。人口统计信息字符串表示Race / Gender / Age,NaNs 由文字问号表示。这是我想去的地方:
res = {
'Joe Schmoe': {
'race': 'W',
'gender': 'M',
'age': 64,
'officer': False
},
'Richard Johnson': {
'race': 'W',
'gender': 'M',
'age': 48,
'officer': True
},
'Adrian Stevens': {
'race': 'NaN',
'gender': 'NaN',
'age': 27,
'officer': False
}
}
现在我已经构建了两个函数来执行此操作。第一个在下面并处理 Demographic Info 字符串。 (这个我没问题;只是放在这里供参考。)
import re
def fix_demographic(info):
# W / M / ?? --> W / M / NaN
# ?/M/? --> NaN / M / NaN
# Keep as str NaN rather than np.nan for now
race, gender, age = re.split('\s*/\s*', re.sub('\?+', 'NaN', info))
return race, gender, age
第二个函数解构列表并将其值扔到字典结果中的不同位置:
demographic = re.compile(r'(\w+|\?+)\s*\/\s*(\w+|\?+)\s*\/\s*(\w+|\?+)')
def parse_victim_info(info: list):
res = defaultdict(dict)
for i in info:
if not demographic.fullmatch(i) and i.lower() != 'officer':
# We have a name
previous = 'name'
name = i
if i.lower() == 'officer':
res[name]['officer'] = True
previous = 'officer'
if demographic.fullmatch(i):
# We have demographic info; did "OFFICER" come before it?
if previous == 'name':
res[name]['officer'] = False
race, gender, age = fix_demographic(i)
res[name]['race'] = race
res[name]['gender'] = gender
res[name]['age'] = int(age) if age.isnumeric() else age
previous = None
return res
>>> parse_victim_info(info)
defaultdict(dict,
{'Adrian Stevens': {'age': 27,
'gender': 'NaN',
'officer': False,
'race': 'NaN'},
'Richard Johnson': {'age': 48,
'gender': 'M',
'officer': True,
# ... ...
第二个函数感觉太冗长乏味了。
有没有更好的方法可以更智能地记住迭代中看到的最后一个值的分类?
【问题讨论】:
-
这种问题你别无选择,只能卷起袖子,因为糟糕的设计而放弃编写糟糕的代码:(
标签: python dictionary nested defaultdict