我正在尝试根据条件作为字典中值的类型将字典列表分为两个列表。无论如何,可以通过一次通过列表理解吗?
当前,我正在这样做:
nonvals = [{k: v for k, v in act.items() if type(v) != int} for act in actual]
vals = [{k: v for k, v in act.items() if type(v) == int} for act in actual]
无论如何,我是否可以基于一个列表理解中的条件返回两个列表?如果不是,那么分割此字典列表的更Python方式是什么?
我正在尝试做以下事情作为最终解决方案,但是我觉得可以避免很多代码重复和多余的循环-actual
和expected
都供参考的字典。我想以最少的行数得出最终解决方案。
我要检查非int键,期望的值对是否在非int键,实际的值对中。实际上,我只想检查所有int键,值对是否在[-11,11]范围内。
expected = [{'time': '12:34:22', 'place': 'LA', 'person': 'Mike', 'val1': 2, 'val2': 3, 'val3': 4},
{'time': '11:45:15', 'place': 'SF', 'person': 'Emily', 'val1': 2, 'val2': 3, 'val3': 4}]
actual = [{'time': '12:34:22', 'place': 'LA', 'person': 'Mike', 'val1': 2, 'val2': 3, 'val3': 4},
{'time': '11:45:15', 'place': 'SF', 'person': 'Emily', 'val1': 2, 'val2': 3, 'val3': 4},
{'time': '21:19:57', 'place': 'LA', 'person': 'Leo', 'val1': 2, 'val2': 3, 'val3': 4},
{'time': '15:43:11', 'place': 'LA', 'person': 'Marge', 'val1': 2, 'val2': 3, 'val3': 4}]
def check(expected, actual):
nonvals = [{k: v for k, v in act.items() if type(v) != int} for act in actual]
vals = [{k: v for k, v in act.items() if type(v) == int} for act in actual]
for act in actual:
for k, v in act.items():
if v in vals and v not in range(-11, 11):
return False
for exp in expected:
if {k: v for k, v in exp.items() if type(v) != int} not in nonvals:
return False
return True
答案 0 :(得分:1)
没有通用的pythonic解决方案可以根据某种条件拆分列表,更不用说根据某种条件(如与特定类型匹配的值的类型)拆分字典的工作了。 >
做的事情很容易读懂,而且不是一个不好的解决方案,但是如果您经常遇到此问题,则可以编写一个函数,然后将其应用于列表中的字典:
def pdict(d, condition):
"""
Partition a dictionary based on some condition function
:param d: a dict
:param condition: a function with parameters k, v returning a bool for k: v in d
:return: two dictionaries, with the contents of d, split according to condition
"""
return {
k: v for k, v in d.items() if condition(k, v)
}, {
k: v for k, v in d.items() if not condition(k, v)
}
original = [{'a': 1, 'b': 'two', 'c': 3}, {'a': 'one', 'b': 2}, {'a': 1, 'b': 2}]
int_result, nonint_result = [
list(t) for t in zip(*[
pdict(d, lambda k, v: isinstance(v, int)) for d in original
])
]
print(int_result)
print(nonint_result)
这很干净,您可以在类似情况下简单地重用partition_dict
。
该示例产生的输出:
[{'a': 1, 'c': 3}, {'b': 2}, {'a': 1, 'b': 2}]
[{'b': 'two'}, {'a': 'one'}, {}]
(重新)使用pdict()
的更简单示例:
d = {1: 42, 2: 33, 3: 5, 4: 10}
odd, even = pdict(d, lambda k, v: v % 2 == 1)
print(odd, even)
输出:
{2: 33, 3: 5} {1: 42, 4: 10}
对pdict()
的重写仅循环一次(如@blues所建议),但有点冗长:
def pdict(d, condition):
"""
Partition a dictionary based on some condition function
:param d: a dict
:param condition: a function with parameters k, v returning a bool for k: v in d
:return: two dictionaries, with the contents of d, split according to condition
"""
meets_condition = {}
does_not_meet_condition = {}
for k, v in d.items():
if condition(k, v):
meets_condition[k] = v
else:
does_not_meet_condition[k] = v
return meets_condition, does_not_meet_condition
这样的缺点可能是,对于每个添加到字典的元素,查找中可能会有一些开销,原始示例代码可以避免字典理解中的开销。您可以运行性能测试来确定最佳选择,但是后一种解决方案的确避免了遍历整个原始字典两次。我想我希望第一个解决方案不是所有疯狂的事情。