将列表拆分为相等值的较小列表

时间:2017-06-19 22:40:45

标签: python

我希望将列表转换为相等值的较小列表。我的一个例子是:

["a", "a", "a", "b", "b", "c", "c", "c", "c"] 

[["a", "a", "a"], ["b", "b"], ["c", "c", "c", "c"]]

您认为最有效的方法是什么?

4 个答案:

答案 0 :(得分:3)

您可以使用itertools.groupby来解决问题:

>>> from itertools import groupby
>>> [list(grp) for k, grp in groupby(["a", "a", "a", "b", "b", "c", "c", "c", "c"])]
[['a', 'a', 'a'], ['b', 'b'], ['c', 'c', 'c', 'c']]

它只对连续的相等元素进行分组,但在您的情况下这似乎已经足够了。

答案 1 :(得分:3)

您可以使用public class Class1 { public int Post_ID { get; set; } public string Post1 { get; set; } public int cmtcount { get; set; } }

collections.Counter

即使未对值进行排序并且提供非常紧凑的表示,然后您可以根据需要将其展开到列表中,这也可以工作:

>>> lst = ["a", "a", "a", "b", "b", "c", "c", "c", "c"]
>>> import collections
>>> collections.Counter(lst).most_common()
[('c', 4), ('a', 3), ('b', 2)]

答案 2 :(得分:1)

获得所需输出的另一种方法是使用defaultdict模块中的collections(使用此方法的最佳时间是:〜= 0.02s与使用groupby相同):

from collections import defaultdict
a = ["a", "a", "a", "b", "b", "c", "c", "c", "c"]
b = defaultdict(list)
for k in a:
    b[k].append(k)

>>> b 
defaultdict(list,
            {'a': ['a', 'a', 'a'], 'b': ['b', 'b'], 'c': ['c', 'c', 'c', 'c']})

所以,你现在要做的是:

list(b.values())
>>> [['a', 'a', 'a'], ['b', 'b'], ['c', 'c', 'c', 'c']]

答案 3 :(得分:0)

虽然我个人使用itertools.groupby作为最方便的方式,但您已经要求效率,这应该比任何itertools选项快得多:

data = ["a", "a", "a", "b", "b", "c", "c", "c", "c"] 

lookup = {}  # lookup map
result = []
for element in data:
    if element not in lookup:
        target = lookup[element] = [element]
        result.append(target)
    else:
        lookup[element].append(element)

print(result)
# [['a', 'a', 'a'], ['b', 'b'], ['c', 'c', 'c', 'c']]

如果数据总是有序的(即元素不混合),可以在没有查找表的情况下进一步优化,并使用列表推导来获得最佳性能。

更新 - 对效率和运营的一些说明。如果您将测试设置为:

from itertools import groupby

def itools_func(data):
    return [list(grp) for k, grp in groupby(data)]

def manual_func(data):
    lookup = {}
    result = []
    for element in data:
        if element not in lookup:
            target = lookup[element] = [element]
            result.append(target)
        else:
            lookup[element].append(element)
    return result

问题是这两个不会返回相同的值:

test_data = ["a", "a", "b", "c", "c", "b", "a"]

itools_func(test_data)  # [['a', 'a'], ['b'], ['c', 'c'], ['b'], ['a']]
manual_func(test_data)  # [['a', 'a', 'a'], ['b', 'b'], ['c', 'c']]

从OP的问题来看,我理解他想要后者(根据他的评论“我对列表进行排序以使值连续”),因为使用排序列表可以更容易地完成。所以,如果我们为这些函数提供一个非常长的列表:

test_data = ["a", "a", "a", "b", "b", "c", "c", "c", "c"] * 10000  # 10000 x the original

在我的系统上,它的时钟如下:

itools_func - 100 loops: 2.668s, per loop: 26.68ms
manual_func - 100 loops: 1.005s, per loop: 10.05ms

但是,这对itertools.groopby来说是一个不利的设置。如果数据的排序方式如下:

test_data = ["a"] * 3000 + ["b"] * 2000 + ["c"] * 40000

随着C后端的开始,故事有点不同:

itools_func - 1000 loops: 656.3ms, per loop: 656.3µs
manual_func - 1000 loops: 4.816s, per loop: 4.816ms

当对数据进行排序时,可以进一步优化手动功能,但它几乎不会超过itertools引导下的功能。