我有一个独特对象的平面列表,其中一些可能与其他对象共享一个给定的属性.我希望创建一个嵌套的列表列表,其中对象按给定属性分组.作为一个最小的例子,给出以下列表:
>>> flat = ["Shoes", "pants", "shirt", "tie", "jacket", "hat"]
Run Code Online (Sandbox Code Playgroud)
我可能想按长度分组,例如:
>>> nest_by_length(flat)
[['tie', 'hat'], ['shoes', 'pants', 'shirt'], ['jacket']]
Run Code Online (Sandbox Code Playgroud)
我见过几个类似的 问题和建议.但是,在所有这些情况下,嵌套都基于输入列表的顺序.在我的例子中,输入列表的排序是完全不可预测的,输出的子列表的数量和每个子列表的项目数量也是如此.
是否有标准功能或惯用方法来实现这一目标?
daw*_*awg 11
现有列表的常用习惯是在itertools中使用groupby:
from itertools import groupby
flat = ["Shoes", "pants", "shirt", "tie", "jacket", "hat"]
result=[]
for k, g in groupby(sorted(flat, key=len), key=len):
result.append(list(g))
print result
Run Code Online (Sandbox Code Playgroud)
或者,更简洁:
[list(g) for _,g in groupby(sorted(flat, key=len), key=len)]
Run Code Online (Sandbox Code Playgroud)
打印:
[['tie', 'hat'], ['Shoes', 'pants', 'shirt'], ['jacket']]
Run Code Online (Sandbox Code Playgroud)
groupby在这种情况下,输入到基于键函数输出的变化值被分组len.通常,您需要根据相同的键函数对列表进行预排序,因此sorted首先调用该函数.
如果您的源列表尚未完成,或者根据条件无法排序(或者您只是喜欢其他选项),请创建一个将您的条件映射到唯一键值的dict:
groups={}
for e in flat:
groups.setdefault(len(e), []).append(e)
print groups
# {5: ['Shoes', 'pants', 'shirt'], 3: ['tie', 'hat'], 6: ['jacket']}
Run Code Online (Sandbox Code Playgroud)
您还可以将defaultdict而不是setdefault与任意键值一起使用:
from collections import defaultdict
groups=defaultdict(list)
for e in flat:
groups[len(e)].append(e)
# groups=defaultdict(<type 'list'>, {5: ['Shoes', 'pants', 'shirt'], 3: ['tie', 'hat'], 6: ['jacket']})
Run Code Online (Sandbox Code Playgroud)
在任何一种情况下,您都可以从中创建嵌套列表:
>>> [groups[k] for k in sorted(groups.keys())]
[['tie', 'hat'], ['Shoes', 'pants', 'shirt'], ['jacket']]
Run Code Online (Sandbox Code Playgroud)