如何通过Python生成给定对象列表的成员字典?

时间:2019-02-11 16:51:49

标签: python dictionary set

我有一个此类的对象列表:

class foo:
    def __init__(self,x,y):
        self.x = x
        self.y = y
    def __repr__(self):
        return "(" + str(self.x) + "," + str(self.y) + ")"

现在,我想创建一个字典,其中包含x的每个值的列表(排序的,唯一的元素),其中包含y的值。我写了这个

def get_xy_dict(lis):
    outp = {}
    for e in lis:
        if (e.x in outp): 
            outp[e.x].add(e.y)
        else:
            outp[e.x] = set([e.y])
    return outp

像这样使用它,可以按预期工作:

x = [ foo(1,2), foo(1,3), foo(3,6), foo(1,3)]
y = get_xy_dict(x)
print(x)
print(y)

打印(请参见here):

[(1,2), (1,3), (3,6), (1,3)]                                                                                                                                                                  
{1: {2, 3}, 3: {6}}   

但是,我觉得我的代码非常笨拙。而且,我更喜欢列表而不是集合。也许可以完全避免使用这些集。也是出于巧合,对输出进行了排序,如果再加上它,它将变得更加笨拙。

获得相同输出(最好是列表而不是集合)的pythonic方法是什么?即,如何生成包含给定y出现的所有x值的字典?

PS:不确定,如果这属于codereview,请告诉我。

2 个答案:

答案 0 :(得分:2)

您首先需要按 x 属性对foo项目进行排序,然后才能对它们进行分组。

一种方法是使用itertools.groupby,如下所示:

import itertools
import operator


sort_key = operator.attrgetter('x')
y = {k: set(v.y for v in group)
     for k, group in itertools.groupby(sorted(x, key=sort_key), sort_key)}
print(y)

您得到:

{1: {2, 3}, 3: {6}}

答案 1 :(得分:1)

您可以使用sorted功能轻松地将集合更改为排序列表。与defaultdict结合使用,您可以大大简化代码:

from collections import defaultdict

def get_xy_dict(lis):
    d = defaultdict(set)
    for e in lis:
        d[e.x].add(e.y)
    return {k: sorted(v) for k, v in d.items()}  # This creates a new dict, but you could also 
                                                 # change the values of d

x = [ foo(1,2), foo(1,3), foo(3,6), foo(1,3)]
y = get_xy_dict(x)
print(x)  # [(1,2), (1,3), (3,6), (1,3)]
print(y)  # {1: [2, 3], 3: [6]}