我有一种通过键将字典列表分组的方法。为此,我发现here必须使用groupby
函数,但必须对列表进行排序。这是我现在的方法:
def group_list_by_key(data, key):
data.sort(key=lambda x: x[key])
result = []
for k, v in groupby(data, key=lambda x: x[key]):
result.append(list(v))
return result
仅当在所有字典中定义了每个键并且值都属于同一类型时,这段代码才有效。但是,在使用这种方法的地方,我不知道该密钥是否在各处定义,并且它们是否属于同一类型。在Python 2.x上,我知道存在带有cmp
参数的sorted
函数,该函数可以进行自定义排序,但是从Python 3.x开始,这已经不可能了。有没有办法进行自定义排序?我正在考虑使用通过<
进行的经典排序以及通过类型名进行的排序。
现在,我考虑使用get函数并将其转换为类似这样的字符串
data.sort(key=lambda x: str(x.get(key)))
...
for k, v in groupby(data, key=lambda x: x.get(key)):
仅克服了字符串,数字和无内容的情况,但克服了通用对象,例如在我执行时很容易破坏
a = [{'b': 0, 'c': 1}, {'b': '0'}, {'b': 0, 'c': 2}, {'b': 1}, {'c': 3}]
group_list_by_key(a, 'b')
输出为
[[{'b': 0, 'c': 1}], [{'b': '0'}], [{'b': 0, 'c': 2}], [{'b': 1}], [{'c': 3}]]
而不是我的预期(列表顺序不是问题)
[[{'b': 0, 'c': 1}, {'b': 0, 'c': 2}], [{'b': '0'}], [{'b': 1}], [{'c': 3}]]
答案 0 :(得分:2)
您可以通过执行以下操作来解决问题
data = [{'b': 0, 'c': 1}, {'b': '0'}, {'b': 0, 'c': 2}, {'b': 1}, {'c': 3}]
key='b'
def f(x):
ret = x.get(key, -1)
return ret if type(ret) == int else -2
result = [list(v) for k, v in groupby(sorted(data, key=f), f)]
# result: [[{'b': '0'}], [{'c': 3}], [{'b': 0, 'c': 1}, {'b': 0, 'c': 2}], [{'b': 1}]]
但是,如果您仍然需要自定义比较功能,则可以使用functools.cmp_to_key
import functools
sorted(x, key=functools.cmp_to_key(custom_cmp_function))
答案 1 :(得分:0)
感谢@Sunitha和@ njzk2指出了cmp_to_key函数,它完全可以实现我想要的功能。所以,我现在的分组是:
from functools import cmp_to_key
from itertools import groupby
def group_list_by_key(data, key):
def compare_values_types(a, b):
a = a.get(key)
b = b.get(key)
if a.__class__ == b.__class__:
if a < b:
return -1
elif a > b:
return 1
else:
return 0
else:
if a.__class__.__name__ < b.__class__.__name__:
return -1
elif a.__class__.__name__ > b.__class__.__name__:
return 1
else:
return 0
data.sort(key=cmp_to_key(compare_values_types))
return [list(v) for k, v in groupby(data, key=lambda x: x.get(key))]
调用样本列表
a = [{'b': 0, 'c': 1}, {'b': '0'}, {'b': 0, 'c': 2}, {'b': 1}, {'c': 3}]
group_list_by_key(a, 'b')
它返回预期的列表
[[{'c': 3}], [{'b': 0, 'c': 1}, {'b': 0, 'c': 2}], [{'b': 1}], [{'b': '0'}]]
我所做的是以经典方式比较相同类型的键,否则,我只是在类名称之间进行字符串比较(使用a.__class__.__name__
而不是type(a).__name__
,请检查answer)。
谢谢大家!