如何在 python3 中按姓氏对全名字典键进行排序和分组?



我想按键对字典进行排序和分组。 键目前是全名,但我想将所有相似的姓氏组合在一起并组合它们的值对。 输入词典的摘录如下:

facdict = {'Yimei Li': [' Ph.D.', 'Assistant Professor of Biostatistics', 'liy3@email.chop.edu'], 
'Mingyao Li': [' Ph.D.', 'Associate Professor of Biostatistics', 'mingyao@mail.med.upenn.edu'], 
'Hongzhe Li': [' Ph.D', 'Professor of Biostatistics', 'hongzhe@upenn.edu'], 
'A. Russell Localio': [' JD MA MPH MS PhD', 'Associate Professor of Biostatistics', 'rlocalio@upenn.edu']}

所需的输出为:

last_name_dict = {'Li': [[' Ph.D.', 'Assistant Professor of Biostatistics', 'liy3@email.chop.edu'], [' Ph.D.', 'Associate Professor of Biostatistics', 'mingyao@mail.med.upenn.edu'], [' Ph.D', 'Professor of Biostatistics', 'hongzhe@upenn.edu']], 
'Localio': [' JD MA MPH MS PhD', 'Associate Professor of Biostatistics', 'rlocalio@upenn.edu']}

我尝试使用以下字典理解:

search = re.compile(r"([A-Z]{1}[a-z]+)")
last_name_dict = {k.replace(k, search.findall(k)[-1:][0]): v for k, v in facdict.items()}

但这返回每个条目的姓氏,其中只有第一个与之关联的值对。

字典推导只能生成单个键值对;任何重复的对都不会组合,而只是替换同一键的先前值。

只需使用常规循环,并使用dict.setdefault()初始化外部列表:

last_name_dict = {}
for k, v in facdict.items():
last_name = k.replace(k, search.findall(k)[-1:][0])
last_name_dict.setdefault(last_name, []).append(v)

dictionary.setdefault(key, [])在字典中查找密钥并返回它。但是,如果尚未设置键,则在返回该对象之前,第二个参数用于首先设置值。所以在上面的代码中,last_name_dict.setdefault(...)的返回值总是返回一个列表,所以我们可以调用.append(...)并添加另一个条目。

如果您不介意不会因错误的键而出现键错误,则可以使用collections.defaultdict()对象:

from collections import defaultdict
last_name_dict = defaultdict(list)
for k, v in facdict.items():
last_name = k.replace(k, search.findall(k)[-1:][0])
last_name_dict[last_name].append(v)

考虑到last_name_dict[unknown_key]将创建另一个列表对象并返回该对象。

如果您首先对姓氏的输入进行排序,然后按相同的姓氏值对输入进行分组,则可以使用字典理解实现相同的itertools.groupby(),但这效率不高。上述解决方案以O(N(线性时间对输入进行分组;对于 10 个项目,您采取 10 个步骤,对于 100 个项目,您需要 100 个步骤,依此类推。排序需要 O(NlogN( 准线性时间,其中 10 个项目大约需要 33 个步骤,100 个项目大约需要 664 个步骤,依此类推。排序步骤是否更快不再重要,随着输入数量的增加,与不需要排序时相比,需要排序时的步骤数量增长得更快,因此无论如何最终都会变慢。

最新更新