将非结构化名称和数据列表转换为嵌套字典

布拉德·所罗门

我有一个看起来像这样的“非结构化”列表:

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
        }
    }

现在,我已经构建了两个函数来执行此操作。第一个在下面,并处理“人口统计信息”字符串。(我对此很满意;只需将其放在此处以供参考。)

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,
              # ... ...

第二个功能对于正在执行的操作来说太冗长乏味。

有没有更好的方法可以更好地记住迭代中最后一个值的分类?

斯蒂芬·劳奇

这种事情非常适合发电机

码:

def find_triplets(data):
    data = iter(data)
    while True:
        name = next(data)
        demo = next(data)
        officer = demo == 'OFFICER'
        if officer:
            demo = next(data)
        yield name, officer, demo

测试代码:

info = [
    'Joe Schmoe',
    'W / M / 64',
    'Lillian Schmoe',
    'W / F / 60',
    'Richard Johnson',
    'OFFICER',
    'W / M /48',
    'Adrian Stevens',
    '? / ? / 27'
]

for x in find_triplets(info):
    print(x)

结果:

('Joe Schmoe', False, 'W / M / 64')
('Lillian Schmoe', False, 'W / F / 60')
('Richard Johnson', True, 'W / M /48')
('Adrian Stevens', False, '? / ? / 27')

将元组三元组转换为dict

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 dict(race=race, gender=gender, age=age)


data_dict = {name: dict(officer=officer, **fix_demographic(demo))
             for name, officer, demo in find_triplets(info)}

print(data_dict)

结果:

{
    'Joe Schmoe': {'officer': False, 'race': 'W', 'gender': 'M', 'age': '64'}, 
    'Lillian Schmoe': {'officer': False, 'race': 'W', 'gender': 'F', 'age': '60'}, 
    'Richard Johnson': {'officer': True, 'race': 'W', 'gender': 'M', 'age': '48'}, 
    'Adrian Stevens': {'officer': False, 'race': 'NaN', 'gender': 'NaN', 'age': '27'}
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章