如何重新安排这样的列表(python)?

Sha*_*ane 3 python algorithm list

例如,列表to_be包括:3 "a"个中的"b"3 个,3 个中的3 "c"个,"d"...

to_be = ["a", "a", "a", "b", "b", "b", "b", "c", "c", "c", "d", "d", "d", "d", "d", ...]
Run Code Online (Sandbox Code Playgroud)

现在我希望它是这样的:

done = ["a", "b", "c", "d", ... , "a", "b", "c", "d", ... , "b", "d", ...] (notice: some items are more than others as in amounts, but they need to be still in a pre-defined order, alphabetically for example)
Run Code Online (Sandbox Code Playgroud)

最快的方法是什么?

Gar*_*tty 12

假设我理解你想要的东西,它可以通过组合相对容易地完成itertools.zip_longest,itertools.groupby并且itertools.chain.from_iterable():

我们首先将项目分组("a"s,"b"s等等),我们将它们压缩以按照您想要的顺序(每组一个),使用链生成单个列表,然后删除None压缩引入的值.

>>> [item for item in itertools.chain.from_iterable(itertools.zip_longest(*[list(x) for _, x in itertools.groupby(to_be)])) if item]
['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'b', 'd', 'd']
Run Code Online (Sandbox Code Playgroud)

您可能希望将一些列表推导分开,以使其更具可读性,但是:

>>> groups = itertools.zip_longest(*[list(x) for _, x in itertools.groupby(to_be)])
>>> [item for item in itertools.chain.from_iterable(groups) if item]
['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'b', 'd', 'd']
Run Code Online (Sandbox Code Playgroud)

(给定版本为3.x,对于2.x,您需要izip_longest().)

与往常一样,如果您期望空字符串,0等等,那么您将要做if item is not None,如果您需要保持None值,请创建一个sentinel对象并检查其身份.

您也可以使用文档中给出roundrobin()配方作为压缩的替代方法,这使得它简单如下:

>>> list(roundrobin(*[list(x) for _, x in itertools.groupby(to_be)]))
['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'b', 'd', 'd']
Run Code Online (Sandbox Code Playgroud)

作为最后一点,观察者可能会注意到我从groupby()生成器制作列表,这可能看起来很浪费,原因来自文档:

返回的组本身是一个迭代器,它使用groupby()共享底层的iterable.由于源是共享的,因此当groupby()对象处于高级时,前一个组将不再可见.因此,如果稍后需要该数据,则应将其存储为列表.

  • 比我的解决方案更优雅.奖励! (2认同)