Python 按对象特征创建列表字典

Python 按对象特征创建列表字典,python,arrays,Python,Arrays,假设我有一门课: class Cat(object): color = "White" # "Black", "Red" or whatever name = "..." .... 如果我有一个猫的列表,我想按颜色将它们分开,并放入列表字典: cats = [cat1, cat2, cat3, ...] cats_by_color = {"White": [cat1, cat3, ...], "Black": [...], ...} 现在我这样做: ca

假设我有一门课:

class Cat(object):
     color = "White"     # "Black", "Red" or whatever
     name = "..."
     ....
如果我有一个猫的列表,我想按颜色将它们分开,并放入列表字典:

cats = [cat1, cat2, cat3, ...]
cats_by_color = {"White": [cat1, cat3, ...], "Black": [...], ...}
现在我这样做:

cats_by_color ={}
for cat in cats:
    if cat.color not in cats_by_color.keys():    # add new key if needed
        cats_by_color[cat.color] = []
    cats_by_colors[cat.color].append(cat)        # add cat to right list

我有一种强烈的感觉,做这样的事情有一种“更像pythonish的方式”。如何做到这一点的一些班轮

要在一行中完成,您需要先对列表进行排序,然后使用:

from collections import defaultdict
cats_by_color = defaultdict(list)

for cat in cats:
    cats_by_colors[cat.color].append(cat)
然而,排序比直接循环的成本更高;这不再是一个单衬里,但使用至少使其紧凑:

from collections import defaultdict

cats_by_color = defaultdict(list)

for cat in cats:
    cats_by_colors[cat.color].append(cat)

这里,
defaultdict
将为字典中尚未包含的键创建一个新的
list
对象,只需尝试访问该键。

要在一行中完成此操作,您需要先对列表排序,然后使用:

然而,排序比直接循环的成本更高;这不再是一个单衬里,但使用至少使其紧凑:

from collections import defaultdict

cats_by_color = defaultdict(list)

for cat in cats:
    cats_by_colors[cat.color].append(cat)

在这里,
defaultdict
将为尚未在字典中的键创建一个新的
列表
对象,只需尝试访问该键。

如果您确实希望它在一行中,而不需要任何导入:

cats_by_colors = {color: [cat for cat in cats if cat.color == color] 
                  for color in set(cat.color for cat in cats)}
但是,由于这会对所有的
进行迭代,因此对于每种
颜色
(以及一次获取颜色),这不是很有效

请注意,您的
Cat
属性当前是类,而不是实例属性,应该是:

class Cat:
    def __init__(self, color, name):
        self.color = color
        self.name = name

如果您确实希望它在一行中,而不需要任何导入:

cats_by_colors = {color: [cat for cat in cats if cat.color == color] 
                  for color in set(cat.color for cat in cats)}
但是,由于这会对所有的
进行迭代,因此对于每种
颜色
(以及一次获取颜色),这不是很有效

请注意,您的
Cat
属性当前是类,而不是实例属性,应该是:

class Cat:
    def __init__(self, color, name):
        self.color = color
        self.name = name


如果cat.color不在cats\u by\u color.keys():#如果需要添加新的键cats\u by\u color[cat.color]=[]
可以替换为
默认的dict
,首先,它们也是
itertools.groupby
,但它需要一个排序列表。如果cat.color不在cats\u by\u color.keys():#根据需要添加新键cats by_color[cat.color]=[]可以替换为
默认dict
,首先,它们也是
itertools.groupby
,但需要排序列表。神圣指数列表迭代!你知道你现在是N平方次循环了,对吗?除非每只猫都有不同的颜色。。。我会注意到,虽然这是整洁的,但它不是有效的!
set()
production是一个完整的
N
迭代,然后N次迭代的子集将再次执行
N
的完整循环。不完全是N平方,但远没有效率。@MartijnPieters我希望,即使猫的数量变得非常大,离散颜色的数量也会保持很小(~
O(1)
),因此我会得到
O(N)
的整体性能。我建议绝育以保持
n
小!你最多只能得到O(KN),其中K是唯一的猫的颜色数。groupby解决方案是O(NlogN),我敢打赌在大多数情况下logN将小于K。确定独特颜色的数量将花费更多(构建集合)。神圣指数列表迭代!你知道你现在是N平方次循环了,对吗?除非每只猫都有不同的颜色。。。我会注意到,虽然这是整洁的,但它不是有效的!
set()
production是一个完整的
N
迭代,然后N次迭代的子集将再次执行
N
的完整循环。不完全是N平方,但远没有效率。@MartijnPieters我希望,即使猫的数量变得非常大,离散颜色的数量也会保持很小(~
O(1)
),因此我会得到
O(N)
的整体性能。我建议绝育以保持
n
小!你最多只能得到O(KN),其中K是唯一的猫的颜色数。groupby解决方案是O(NlogN),我敢打赌在大多数情况下logN将小于K。确定独特颜色的数量将花费更多(制作布景)。@mgilson:不过你错过了帖子中的另一个错误:-P(在
groupby()
调用中没有右括号)。如何
(lambda d={}:[d.setdefault(c.color,[])。在cats中为c添加(c)和d)(
对于no-import 1 liner.Ick,副作用的列表理解!我的神圣符号和花环在哪里!我试图找出如何把它变成一个真正的一行-这是我唯一能想到的方法。但无论如何,我真正的目的是使用defaultdict。。。不需要为了满足一些愚蠢的“1-liner”需求而引入O(nlogn)算法。在这一点上,我反反复复,但当我真实地面对自己时,我认为回答“给我一行”的问题对语言来说并不是最好的——它让人觉得一行比多行要好,而不是追求好的、惯用的python。@mgilson:我同意;我在回答中解释了为什么这不是一个好主意。@mgilson:不过你错过了帖子中的另一个打字错误-P(在
groupby()
调用中没有右括号)。如何
(lambda d={}:[d.setdefault(c.color,[])。在cats中为c添加(c)和d)(
对于no-import 1 liner.Ick,副作用的列表理解!我的神圣符号和花环在哪里!我试图找出如何把它变成一个真正的一行-这是我唯一能想到的方法。但无论如何,我真正的目的是使用defaultdict。。。不需要为了满足一些愚蠢的“1-liner”需求而引入O(nlogn)算法。在这一点上,我反反复复,但当我真实地面对自己时,我认为回答“给我一行”的问题对语言来说并不是最好的——它让人觉得一行比多行要好,而不是追求好的、惯用的python。@mgilson:我同意;我在ans中解释了为什么这不是一个好主意