我有一个字典列表,我想循环排序。
sample = [
{'source': 'G', '"serial"': '0'},
{'source': 'G', '"serial"': '1'},
{'source': 'G', '"serial"': '2'},
{'source': 'P', '"serial"': '30'},
{'source': 'P', '"serial"': '0'},
{'source': 'P', '"serial"': '1'},
{'source': 'P', '"serial"': '2'},
{'source': 'P', '"serial"': '3'},
{'source': 'T', '"serial"': '2'},
{'source': 'T', '"serial"': '3'}
]
我想要这个结果:
sample_solved = [
{'source': 'G', '"serial"': '0'},
{'source': 'P', '"serial"': '30'},
{'source': 'T', '"serial"': '2'},
{'source': 'G', '"serial"': '1'},
{'source': 'P', '"serial"': '1'},
{'source': 'T', '"serial"': '3'},
{'source': 'G', '"serial"': '2'},
{'source': 'P', '"serial"': '0'},
{'source': 'P', '"serial"': '2'},
{'source': 'P', '"serial"': '3'}
]
我解决它的方法如下:
def roundrobin(*iterables):
# took from here https://docs.python.org/3/library/itertools.html#itertools-recipes
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
# Recipe credited to George Sakkis
pending = len(iterables)
nexts = cycle(iter(it).__next__ for it in iterables)
while pending:
try:
for next in nexts:
yield next()
except StopIteration:
pending -= 1
nexts = cycle(islice(nexts, pending))
def solve():
items_by_sources = collections.defaultdict(list)
for item in sample2:
items_by_sources[item["source"]].append(item)
t, p, g = items_by_sources.values()
print(list(roundrobin(t, p, g)))
使用Python的defaultdict
按源分隔项目,然后使用我从Python的文档中获得的roundrobin解决方案。
但是,解决方案并未涵盖所有情况,例如t, p, g = items_by_sources.values()
会在缺少一个来源或添加新来源时中断。
如何制定解决方案以覆盖更多边缘情况并使解决方案成为pythonic?
答案 0 :(得分:2)
以下是使用itertools.groupby()
将您的输入拆分为相应组的解决方案:
from itertools import groupby
def grouprobin(iterable, key):
groups = [list(g) for k, g in groupby(iterable, key)]
while groups:
group = groups.pop(0)
yield group.pop(0)
if group:
groups.append(group)
由于groupby()
的工作方式,在您从文档中获取的roundrobin()
版本中巧妙使用迭代器并不是非常有用,因此我已将其重写为一种希望更容易理解的方式:
将可迭代分组为key
虽然您还剩下任何群组:
从组列表的前面弹出第一组
弹出该组中的第一个项目,并将其合并。
如果组中仍有项目,请将其追加到列表末尾。
这是在行动:
>>> sample_solved = list(grouprobin(sample, key=lambda d: d['source']))
>>> from pprint import pprint
>>> pprint(sample_solved)
[{'"serial"': '0', 'source': 'G'},
{'"serial"': '30', 'source': 'P'},
{'"serial"': '2', 'source': 'T'},
{'"serial"': '1', 'source': 'G'},
{'"serial"': '0', 'source': 'P'},
{'"serial"': '3', 'source': 'T'},
{'"serial"': '2', 'source': 'G'},
{'"serial"': '1', 'source': 'P'},
{'"serial"': '2', 'source': 'P'},
{'"serial"': '3', 'source': 'P'}]
上面的grouprobin()
版本假定您的列表已经排序。如果没有,它需要在分组之前进行排序:
def grouprobin(iterable, key):
groups = [list(g) for k, g in groupby(sorted(iterable, key=key), key)]
while groups:
group = groups.pop(0)
yield group.pop(0)
if group:
groups.append(group)