如何将列表中的相同值分组到自己的列表中?

时间:2018-11-22 05:15:16

标签: python list-comprehension

说我有一个列表[2, 3, 7, 2, 3, 8, 7, 3]

我想产生包含与上面列表相同值的列表。

预期输出类似:

[2, 2]
[3, 3, 3]
[7, 7]
[8]

这些列表的生成顺序无关紧要。

7 个答案:

答案 0 :(得分:5)

最好的方法是使用collections.defaultdictO(n)解决方案:

>>> l = [2, 3, 7, 2, 3, 8, 7, 3]
>>> d = defaultdict(list)
>>> for e in l:
...     d[e].append(e)
... 
>>> d
defaultdict(<class 'list'>, {2: [2, 2], 3: [3, 3, 3], 7: [7, 7], 8: [8]})
>>> d.values()
dict_values([[2, 2], [3, 3, 3], [7, 7], [8]])

或者,您可以将itertools.groupby与排序列表一起使用:

>>> for _, l in itertools.groupby(sorted(l)):
...     print(list(l))
... 
[2, 2]
[3, 3, 3]
[7, 7]
[8]

或使用collections.Counter进行列表理解:

>>> from collections import Counter
>>> [[i]*n for i,n in Counter(l).items()]
[[2, 2], [3, 3, 3], [7, 7], [8]]

正如我所张贴的那样,defaultdict解决方案是O(n),并且比其他方法更快。这是测试:

from timeit import timeit


setup = (
"from collections import Counter, defaultdict;"
"from itertools import groupby;"
"l = [2, 3, 7, 2, 3, 8, 7, 3];"
)

defaultdict_call = (
"d = defaultdict(list); "
"\nfor e in l: d[e].append(e);"
)
groupby_call = "[list(g) for _,g in groupby(sorted(l))]"
counter_call = "[[i]*n for i,n in Counter(l).items()]"


for call in (defaultdict_call, groupby_call, counter_call):
  print(call)
  print(timeit(call, setup))

结果:

d = defaultdict(list); 
for e in l: d[e].append(e);
7.02662614302244
[list(g) for _,g in groupby(sorted(l))]
10.126392606005538
[[i]*n for i,n in Counter(l).items()]
19.55539561196929

这里是live test

答案 1 :(得分:4)

尝试一下

l = [2, 3, 7, 2, 3, 8, 7, 3]
for i in set(l):
   print([i]*l.count(i))

输出:

[8]
[2, 2]
[3, 3, 3]
[7, 7]

答案 2 :(得分:3)

这是使用Counter

的一种简短方法
from collections import Counter
my_dict = Counter([2, 3, 7, 2, 3, 8, 7, 3]) # returns {3: 3, 2: 2, 7: 2, 8: 1}

new_list = [[k] * v for k,v in my_dict.items()] 

输出:

[[2, 2], [3, 3, 3], [7, 7], [8]]

答案 3 :(得分:3)

一种方法是使用简单的dictionary

l = [2, 3, 7, 2, 3, 8, 7, 3]

groups = {}
for n in l:
    groups.setdefault(n, []).append(n)

print(list(groups.values()))
# [[2, 2], [3, 3, 3], [7, 7], [8]]

答案 4 :(得分:2)

在Numpy数组中执行此操作会很有效

a= np.array([2, 3, 7, 2, 3, 8, 7, 3])
[a[a==i] for i in np.unique(a)]

输出:

[array([2, 2]), array([3, 3, 3]), array([7, 7]), array([8])]

答案 5 :(得分:2)

我认为您可以尝试使用collections.Counter,并在此列表中获得不同的键及其计数。

from collections import Counter
l = [2, 3, 7, 2, 3, 8, 7, 3]
c =Counter(l)
print(c) ## result: {3: 3, 2: 2, 7: 2, 8: 1} 

答案 6 :(得分:2)

此答案与 列表理解

l = [2, 3, 7, 2, 3, 8, 7, 3]

print(*[[i]*l.count(i) for i in set(l)], sep='\n')

输出:

C:\Users\Desktop>py x.py
[8]
[2, 2]
[3, 3, 3]
[7, 7]

此外,使用sorted()方法可以完全按照您的要求进行输出

l = [2, 3, 7, 2, 3, 8, 7, 3]

print(*sorted([[i]*l.count(i) for i in set(l)]), sep='\n')

输出:

C:\Users\Desktop>py x.py
[2, 2]
[3, 3, 3]
[7, 7]
[8]

编辑::随着答案的增加,我想详细解释代码,以尽我所能。

代码是这样的:

 print(*[[i]*l.count(i) for i in set(l)], sep='\n')

使用set(l)将消除重复的值,并且仅将[2, 3, 7, 8]保留在列表中。稍后,在[i]中,将set(l)的每个元素放入新列表中。我们计算i元素(iset(l中的元素)在本机列表ll = [2, 3, 7, 2, 3, 8, 7, 3])中出现了多少次。并且在[i]*l.count(i) i中成为新列表中的l.count(i)次。列表理解方法在迭代完成后获取所有值,并将其打包在列表中并返回列表。开头的*符号用于解压缩返回列表中的值。最后,*print()*关键字sep='\n'在解压缩列表中的每个元素之后放置一个'\n'。没有它,它可以像这样完成:

for j in [[i]*l.count(i) for i in set(l)]:
    print(j)