我会分两步完成:
>>> import collections
>>> inputs = [1, 2, 2, 2, 3, 1, 1, 3]
>>> counts = collections.Counter(inputs)
>>> counts
Counter({1: 3, 2: 3, 3: 2})
>>> outputs = [[key] * count for key, count in counts.items()]
>>> outputs
[[1, 1, 1], [2, 2, 2], [3, 3]]
(事实上,这些恰好是按数字顺序排序的,而且也是按首次出现的顺序,这只是一个巧合。计数器,像普通字典一样,以任意顺序存储它们的键,你应该假设 @ 987654327@ 可能是一个结果。如果这不可接受,您需要多做一些工作。)
那么,它是如何工作的?
第一步创建一个Counter,它只是dict 的一个特殊子类,用于计算每个键的出现次数。关于它的许多漂亮的事情之一是您可以将任何可迭代的(如list)传递给它,它会计算每个元素出现的次数。这是一个微不足道的单行代码,一旦您知道 Counter 的工作原理,它就很明显且可读,而且它甚至可以达到任何可能的效率。*
但这不是您想要的输出格式。我们如何得到它?好吧,我们必须从1: 3(意思是“1”的3 个副本)返回到[1, 1, 1])。你可以写成[key] * count。**剩下的只是一个沼泽标准的列表理解。
如果您查看 collections 模块的文档,它们会以指向 the source 的链接开头。 stdlib 中的许多模块都是这样的,因为它们旨在用作学习的源代码以及可用的代码。因此,您应该能够弄清楚Counter 构造函数是如何工作的。 (它基本上只是调用 _count_elements 函数。)因为这是 Counter 的唯一部分,您实际上在基本 dict 之外使用,您可以自己编写该部分。 (但实际上,一旦您了解了它的工作原理,就没有理由不使用它,对吧?)
* 对于每个元素,它只是进行哈希表查找(并在需要时插入)和+= 1。而在 CPython 中,这一切都发生在 reasonably-optimized C。
** 请注意,我们不必担心是否在此处使用 [key] * count 与 [key for _ in range(count)],因为值必须是不可变的,或者至少是“相等性与identity" 类型,否则它们将不能用作键。