繁体   English   中英

将默认值添加到有序字典列表

[英]Adding default values to a list of ordered dict

python 3.8

给定一个OrderedDict列表,为列表中所有OrderedList中缺失的所有键设置默认值。 这必须保持顺序。

例子

def add_defaults(list_of_dicts, default_value):
    #implementation goes here
    pass

first = OrderedDict([('k1', 'v1'), ('k2', 'v2'), ('k3', 'v3')])
second = OrderedDict([('k1', 'v1'), ('k2', 'v2'), ('k4', 'v4')])
third = OrderedDict([('k2', 'v2'), ('k5', 'v5'), ('k6', 'v6')])
lst=[first, second, third]
print(add_defaults(lst, ''))

预期 Output (格式化位以简化阅读):

[OrderedDict([('k1', 'v1'), ('k2', 'v2'), ('k3', 'v3'), ('k4', ''), ('k5', ''), ('k6', '')]), 
 OrderedDict([('k1', 'v1'), ('k2', 'v2'), ('k3', ''), ('k4', 'v4'), ('k5', ''), ('k6', '')]), 
 OrderedDict([('k1', ''), ('k2', 'v2'), ('k3', ''), ('k4', ''), ('k5', 'v5'), ('k6', 'v6')])]  

我的实现

def add_defaults(ordered_dict, default_value):
    all_defaults=OrderedDict({}).fromkeys(
            reduce(lambda k, v: OrderedDict(list(k.items()) + list(v.items())), ordered_dict, {}),
            default_value
    )

    results = [OrderedDict(all_defaults) for _ in range(len(ordered_dict))]

    for result, value in zip(results, ordered_dict):
        result.update(value)

    return results

问题

对于这样一个简单的任务,实现看起来过于复杂,而且看起来不像是最简单和 Pythonic 的解决方案。 实现它的惯用方式是什么?

似乎没有 escaping 首先查看所有字典,因为您需要知道要包含哪些键。 您可以通过按顺序将键传递给OrderedDict()来更简单地做到这一点:

default = OrderedDict((k, val) for d in l for k in d.keys())

有了它,您可以混合列表中的字典:

def add_defaults(l, val):
    default = OrderedDict((k, val) for d in l for k in d.keys())
    return [OrderedDict({**default, **d}) for d in l]

first = OrderedDict([('k1', 'v1'), ('k2', 'v2'), ('k3', 'v3')])
second = OrderedDict([('k1', 'v1'), ('k2', 'v2'), ('k4', 'v4')])
third = OrderedDict([('k2', 'v2'), ('k5', 'v5'), ('k6', 'v6')])

lst=[first, second, third]

print(add_defaults(lst, ''))

印刷:

[
 OrderedDict([('k1', 'v1'), ('k2', 'v2'), ('k3', 'v3'), ('k4', ''), ('k5', ''), ('k6', '')]), 
 OrderedDict([('k1', 'v1'), ('k2', 'v2'), ('k3', ''), ('k4', 'v4'), ('k5', ''), ('k6', '')]), 
 OrderedDict([('k1', ''), ('k2', 'v2'), ('k3', ''), ('k4', ''), ('k5', 'v5'), ('k6', 'v6')])
]

是的,这太复杂了。 我只需一次通过即可获得密钥:

allkeys = [k for dct in lst for k in dct]

然后要创建新的有序字典,您可以遍历键并使用.get和默认值:

result = [
    OrderedDict( {k: dct.get(k, '') for k in allkeys } )
    for dct in lst
]

所以,一些一般性的建议,接受还是放弃:


OrderedDict({}).fromkeys(...

您可以只使用OrderedDict.fromkeys(...


在构建新的数据结构时避免reduce Python 的内置类型并不是为您可能会在 Scala 中遇到的那种函数式方法而设计的,该语言在构建时就考虑到了这一点(例如,列表的实现基本上是cons lists )。 您在这里引入了次优行为,使用串联作为归约操作,因为它会导致类似多项式时间的结果。 它也很冗长,迫使您创建中间列表。

 OrderedDict(list(k.items()) + list(v.items()))

说到上面的 lambda,不要一味地使用 python 成语,所以k, v应该指字典键值对,或者类似的东西。 在这里,它是两个字典,reduce 累加器和传入字典。 所以即使是这样的:

lambda acc, d: OrderedDict(list(acc.items()) + list(d.items()))

让读者更好地期待什么。

dict对象还保留添加其键的顺序。 利用此功能,获取初始键列表:

>>> keys = {**first, **second, **third}.keys()
>>> # or
>>> key_d = {}
>>> for d in (first, second, third):
>>>     key_d.update(d)
>>> keys = key_d.keys()

有趣的是,我们用这种方法得到了有序集的效果。 取一个dict并添加键作为具有虚拟值的设置项,然后当您想知道集合中的内容时,只需抓住键即可。 它们将按添加的顺序排列。

使用dict.keys()获得的 object 本身类似于集合并支持一些集合操作; 但是,您会丢失这些操作的顺序,所以first.keys() | second.keys() | third.keys() first.keys() | second.keys() | third.keys() first.keys() | second.keys() | third.keys()将为我们提供键的联合,但不是按照它们在表达式中从左到右遇到的顺序。 然而, {**first, **second, **third}.keys()为我们提供了这个“有序集”的并集 - 相同的效果(但按顺序),不同的语法。

一旦我们有了键,具有默认值的OrderedDict就很容易创建。

>>> new_first = OrderedDict((k, first.get(k, '')) for k in keys)
>>> new_first
OrderedDict([('k1', 'v1'), ('k2', 'v2'), ('k3', 'v3'), ('k4', ''), 
             ('k5', ''), ('k6', '')])

从其他示例中,使用默认字典生成具有默认值的新字典是一个好主意。 这个默认字典实际上不必是OrderedDict本身。

>>> default = {k: '' for d in d_list for k in d.keys()}
>>> new_first = {**default, **first}

new_first现在具有给定顺序的所有键,其中first缺失的键具有默认值。 new_first已经是一个“有序字典”,但如果我们必须将它专门转换为OrderedDict

>>> new_first = OrderedDict(new_first)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM