我希望将列表转换为相等值的较小列表。我的一个例子是:
["a", "a", "a", "b", "b", "c", "c", "c", "c"]
到
[["a", "a", "a"], ["b", "b"], ["c", "c", "c", "c"]]
您认为最有效的方法是什么?
答案 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
引导下的功能。