python:按第一个元素

时间:2017-08-09 09:50:45

标签: performance list list-comprehension ordereddictionary

我有一份清单list1 = [['colour','red'],['colour','blue],['shape','rect'],['shape','square']]

从列表1中制作OrderedDict的最快方法是什么?

{colour:['red','blue'],shape:['rect','square']}

到目前为止,我已经能够通过list1进行映射并提取每个内部列表的索引0中的唯一元素,并将其作为list2返回。

我可以通过list1和list2进行映射,如果找到了maching元素,那么从list1的每个内部列表中获取索引1处的元素,但我不确定它是否是正确的方法/快速方法。

有什么帮助吗?

1 个答案:

答案 0 :(得分:0)

两种方法,取决于您的输入:

选项1:如果在您的示例中,所有匹配的键都是连续的(因此您始终可以看到所有colours),则可以使用itertools.groupby对它们进行分组:

from collections import OrderedDict
from itertools import groupby
from operator import itemgetter

list1 = [['colour','red'],['colour','blue],['shape','rect'],['shape','square']]
dict1 = OrderedDict((k, [v for _, v in grp]) for k, grp in groupby(list1, itemgetter(0)))

这至少在理论上是最快的方法,因为它每次在dict中写入每个键而不会在每次看到一个键时重复查找它,但它依赖于按键排序的输入

选项2:使用__missing__特殊方法在OrderedDict上查找缺失的密钥时使defaultdict(list)具有相同的行为(遗憾的是,这两种类型不兼容,所以你不能创建一个继承自两者的类并在一天内调用它,然后编写一个显式循环来填充它:

from collections import OrderedDict

class OrderedMultidict(OrderedDict):
    __slots__ = ()  # Avoid overhead of per-instance __dict__
    def __missing__(self, key):
        # Missing keys are seamlessly initialized to an empty list
        self[key] = retval = []
        return retval

然后用它来积累结果:

dict1 = OrderedMultidict()
for k, v in list1:
    dict1[k].append(v)

此方法删除了选项1的排序依赖性,以换取添加每个键的重复查找(尽管只有第一个查找调用__missing__中的Python级别代码;之后,如果OrderedDict为C与现代Python 3代码一样,查找也将保持C级别)。也就是说,虽然重复查找在理论上比仅写一次密钥差一些,但实际上我怀疑这个解决方案在现代CPython上会更快(其中OrderedDict是C内置的);在Python 2和更早的Python 3上,它是用Python实现的(虽然groupby总是C级),groupby更有可能获胜,但当两种类型都是C加速时,groupby实际上有一些额外的开销可能会让它失败。