Python:如何按对象的特征或属性对对象列表进行分组? [复制]

Posted

技术标签:

【中文标题】Python:如何按对象的特征或属性对对象列表进行分组? [复制]【英文标题】:Python: How to group a list of objects by their characteristics or attributes? [duplicate] 【发布时间】:2017-01-08 06:25:22 【问题描述】:

我想将对象列表分成子列表,其中具有相同属性/特征的对象保留在同一个子列表中。

假设我们有一个字符串列表:

["This", "is", "a", "sentence", "of", "seven", "words"]

我们想根据字符串的长度来分隔字符串,如下所示:

[['sentence'], ['a'], ['is', 'of'], ['This'], ['seven', 'words']]

我目前想出的程序是这个

sentence = ["This", "is", "a", "sentence", "of", "seven", "words"]
word_len_dict = 
for word in sentence:
    if len(word) not in word_len_dict.keys():
        word_len_dict[len(word)] = [word]
    else:
        word_len_dict[len(word)].append(word)


print word_len_dict.values()

我想知道是否有更好的方法来实现这一点?

【问题讨论】:

以什么方式更好?我个人认为该实现没有问题(假设它有效,我还没有检查过) 由于您的数据未排序,因此您找到了规范方法。您可以改用word_len_dict = defaultdict(list),这样您就不必继续测试密钥是否已经存在。如果您的数据已经排序,请使用itertools.groupby() 或者使用dict.setdefault(),这通常使得使用defaultdict变得不必要。 【参考方案1】:

看看itertools.groupby()。请注意,您的列表必须首先排序(比您的方法 OP 更昂贵)。

>>> from itertools import groupby
>>> l = ["This", "is", "a", "sentence", "of", "seven", "words"]
>>> print [list(g[1]) for g in groupby(sorted(l, key=len), len)]
[['a'], ['is', 'of'], ['This'], ['seven', 'words'], ['sentence']]

或者如果你想要一个字典 ->

>>> k:list(g) for k, g in groupby(sorted(l, key=len), len)
8: ['sentence'], 1: ['a'], 2: ['is', 'of'], 4: ['This'], 5: ['seven', 'words']

【讨论】:

排序是一个 O(NlogN) 操作。使用字典进行分组是 O(N)。仅当数据已排序时才使用groupby。如果没有,请坚持使用 OP 已经设计的方法,因为它会更快(尤其是当要分组的项目数量增加时)。 哦,我完全同意。这就是我记下它的原因。 OP 的方法没有任何问题,只是认为如果速度不是问题/他的数据已经排序,我会提供一个替代方案。【参考方案2】:

使用defaultdict(list),您可以省略密钥存在性检查:

from collections import defaultdict

word_len_dict = defaultdict(list)

for word in sentence:
    word_len_dict[len(word)].append(word)

【讨论】:

【参考方案3】:

itertools.groupby 的文档有一个与您想要的完全匹配的示例。

keyfunc = lambda x: len(x)
data = ["This", "is", "a", "sentence", "of", "seven", "words"]
data = sorted(data, key=keyfunc)
groups = []
for k, g in groupby(data, keyfunc):
    groups.append(list(g))
print groups

【讨论】:

【参考方案4】:

您只能通过使用setdefault 函数对dict 执行此操作:

sentence = ["This", "is", "a", "sentence", "of", "seven", "words"]
word_len_dict = 
for word in sentence:
    word_len_dict.setdefault(len(word), []).append(word)

setdefault 所做的是在您的字典中设置键 len(word)(如果它不存在),并在它存在的情况下检索该值。 setdefault 中的第二个参数是您希望它与该键一起存储的默认值。

请务必注意,如果密钥已存在,则传入 setdefault 的默认值不会替换旧值。这样可以确保每个列表只创建一次,然后setdefault 将检索相同的列表。

【讨论】:

【参考方案5】:

现在我并不是说这在任何方面都更好,除非你认为紧凑的代码更好。您的版本(在 imo 中非常好)更具可读性和可维护性。

list_ = ["This", "is", "a", "sentence", "of", "seven", "words"]

# for python 2 filter returns() a list
result = filter(None,[[x for x in list_ if len(x) == i] for i in range(len(max(list_, key=lambda y: len(y)))+1)])

# for python 3 filter() returns an iterator
result = list(filter(None,[[x for x in list_ if len(x) == i] for i in range(len(max(list_, key=lambda y: len(y)))+1)]))

【讨论】:

【参考方案6】:
sentence = ["This", "is", "a", "sentence", "of", "seven", "words"]
getLength = sorted(list(set([len(data) for data in sentence])))

result = []

for length in getLength:
    result.append([data for data in sentence if length == len(data)])

print(result)

【讨论】:

【参考方案7】:

如果您的目标是用更少的行数完成,总有推导式:

data = ["This", "is", "a", "sentence", "of", "seven", "words"]
# Get all unique length values
unique_length_vals = set([len(word) for word in data])
# Get lists of same-length words
res = [filter(lambda x: len(x) == lval, data) for lval in unique_length_vals]

它可能不太清楚,但如果您只想快速编写代码,它很有用。

【讨论】:

以上是关于Python:如何按对象的特征或属性对对象列表进行分组? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何根据对象的属性对对象列表进行排序?

如何根据对象的属性对对象列表进行排序?

按属性对对象列表进行排序[重复]

按字符串属性C#对对象列表进行排序[重复]

Python入门题045:根据对象属性进行排序

按属性值对对象列表进行排序[重复]