Ale*_*enz 5 python sorting algorithm data-structures python-3.x
我有一个字典列表,我想循环排序.
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'}
]
Run Code Online (Sandbox Code Playgroud)
我想要这个结果:
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'}
]
Run Code Online (Sandbox Code Playgroud)
我解决它的方式如下:
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)))
Run Code Online (Sandbox Code Playgroud)
使用Python defaultdict按源分离项目,然后使用我从Python的文档中获得的roundrobin解决方案.
但是,解决方案并未涵盖所有情况,例如,t, p, g = items_by_sources.values()当缺少一个源或添加新源时会中断.
如何制定解决方案以覆盖更多边缘情况并使解决方案成为pythonic?
这是一个用于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)
Run Code Online (Sandbox Code Playgroud)
由于这种方式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'}]
Run Code Online (Sandbox Code Playgroud)
上面的版本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)
Run Code Online (Sandbox Code Playgroud)