我希望能够在混合类型的字典(包含 int、floats、strings、numpy.arrays)中进行比较。我的最小示例有一个字典列表,我想要一个函数(或生成器)来迭代该列表并挑选包含由 **kwargs 输入到该函数(或生成器)指定的键值对的元素(字典) )。
import re
list_of_dicts = [{'s1':'abcd', 's2':'ABC', 'i':42, 'f':4.2},
{'s2':'xyz', 'i':84, 'f':8.4}]
def find_list_element(**kwargs):
for s in list_of_dicts:
for criterion, criterion_val in kwargs.iteritems():
if type(criterion_val) is str:
if re.match(criterion_val, s.get(criterion, 'unlikely_return_val')):
yield s
continue
if s.get(criterion, None) == criterion_val:
yield s
print [a for a in find_list_element(i=41)] # []
print [a for a in find_list_element(i=42)] # [{'i': 42, 's2': 'ABC', 's1': 'abcd', 'f': 4.2}]
print [a for a in find_list_element(s1='xyz')] # []
print [a for a in find_list_element(s2='xyz')] # [{'i': 84, 's2': 'xyz', 'f': 8.4}]
print [a for a in find_list_element(s2='[a-z]')] # [{'i': 84, 's2': 'xyz', 'f': 8.4}]
我上面的两个问题是:
如果函数要求进行字符串比较,我想切换到正则表达式匹配(re.search 或 re.match),而不是纯字符串比较。在上面的代码中,这是通过辱骂的类型检查完成的,它看起来并不那么优雅。有没有更好的解决方案不涉及类型检查?或者,这是在 python 中允许类型检查的情况?
**kwargs
当然可以包含多个比较。目前我只能想到一个涉及一些标志的解决方案(found = False
切换到 afound = True
并在每次迭代结束时评估list_of_dicts
)。在决定是否屈服之前,有没有一些聪明的方法来累积每个 s 的比较结果?
有没有办法让这整个 dicts 集合更漂亮?
PS:实际用例涉及获取的 MRI 数据集 (BRUKER) 的表示。数据集通过我已转换为表示所述扫描的对象的一部分的 dicts 的参数文件来表征。我正在收集这些数据集,并希望根据这些参数文件给出的某些标准进一步过滤它们。这些参数可以是字符串、数字和其他一些不太方便的类型。
更新和蒸馏答案
如果我想从@BrenBarn 和@srgerg 的输入中得出一个一致的答案,那就是这个
list_of_dicts = [{'s1':'abcd', 's2':'ABC', 'i':42, 'f':4.2},
{'s2':'xyz', 'i':84, 'f':8.4}]
# just making up some comparison strategies
def regex_comp(a,b): return re.match(a,b)
def int_comp(a,b): return a==b
def float_comp(a,b): return round(a,-1) == round (b,-1)
pre_specified_comp_dict = {frozenset(['s1','s2']) : regex_comp,
frozenset(['i']): int_comp,
frozenset(['f']): float_comp}
def fle_new(**kwargs):
chosen_comps={}
for key in kwargs.keys():
# remember, the keys here are frozensets
cand_comp = [x for x in pre_specified_comp_dict if key in x]
chosen_comps[key] = pre_specified_comp_dict[cand_comp[0]]
matches = lambda d: all(k in d and chosen_comps[k](v, d[k])
for k, v in kwargs.items())
return filter(matches, list_of_dicts)
现在唯一的挑战是想出一个无痛的创建策略pre_specified_comp_dict
。