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:如何按对象的特征或属性对对象列表进行分组? [复制]的主要内容,如果未能解决你的问题,请参考以下文章