首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >python根据条件将字典列表拆分为两个列表

python根据条件将字典列表拆分为两个列表
EN

Stack Overflow用户
提问于 2019-06-22 13:47:11
回答 1查看 5.7K关注 0票数 2

我正在尝试根据条件将字典列表拆分为两个列表,条件是字典中的值的类型。有没有办法在一遍列表理解中做到这一点?

目前,我正在做这件事:

代码语言:javascript
复制
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]

有没有什么办法可以在一个列表理解中基于条件返回两个列表?如果不是,还有什么更好的方式来拆分这组字典呢?

我尝试做以下事情作为最终的解决方案,但我觉得有很多代码重复和无关的循环是可以避免的--作为参考,actualexpected都是字典列表。我只想在尽可能少的行数中得到最终的解决方案。

我想检查expected中的非int键,值对是否在非int键,实际值对中。实际上,我只想检查所有的int键,值对是否都在- 11,11范围内。

代码语言:javascript
复制
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
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-06-22 14:15:55

没有通用的pythonic解决方案可以根据某些条件拆分列表,更不用说根据某些条件拆分字典这样更复杂的工作了(比如与特定类型匹配的值的类型)。

做你正在做的事情是相当可读的,也不是一个糟糕的解决方案,但是如果你经常遇到这个问题,你可以只写一个函数,然后你可以应用于列表中的字典:

代码语言:javascript
复制
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

示例产生的输出:

代码语言:javascript
复制
[{'a': 1, 'c': 3}, {'b': 2}, {'a': 1, 'b': 2}]
[{'b': 'two'}, {'a': 'one'}, {}]

(Re)使用pdict()的一个更简单的示例

代码语言:javascript
复制
d = {1: 42, 2: 33, 3: 5, 4: 10}
odd, even = pdict(d, lambda k, v: v % 2 == 1)
print(odd, even)

输出:

代码语言:javascript
复制
{2: 33, 3: 5} {1: 42, 4: 10}

pdict()的重写,它只循环一次(由@blues建议),但用起来有点繁琐:

代码语言:javascript
复制
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

这样做的缺点可能是,对于添加到字典中的每个元素,在查找时可能会有一些开销,而原始示例代码可以在字典理解中避免这些开销。您可以运行性能测试来决定哪种方法更可取,但后一种解决方案避免了两次遍历整个原始字典。我想对于任何不太大的东西,我更喜欢第一个解决方案。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56712929

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档