Oamar Kanji
Oamar Kanji

Reputation: 2224

How to group identical values from a list into their own lists?

Say I have a list [2, 3, 7, 2, 3, 8, 7, 3]

I would like to produce lists that contain identical values from the list above.

Expected Output something like:

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

The order that these lists are produced doesn't matter.

Upvotes: 4

Views: 131

Answers (7)

Netwave
Netwave

Reputation: 42678

Best approach is an O(n) solution with collections.defaultdict:

>>> 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]])

Alternatively you can use itertools.groupby with sorted list:

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

Or a list comprehension with collections.Counter:

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

As I post, the defaultdict solution is O(n) and faster than the other aproaches. Here are the tests:

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))

Results:

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

Here is the live test

Upvotes: 5

Rarblack
Rarblack

Reputation: 4664

This answer is with list-comprehension:

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

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

OUTPUT :

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

Moreover, the output can be made exactly as yours with sorted() method

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

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

OUTPUT:

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

EDIT : As the answer gets upvoted I want to explain the code in detail to be helpful as much as I can.

The code is this:

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

Using set(l) eliminates duplicated values and remains only [2, 3, 7, 8] in the list. Later, in [i] we put each element of set(l) in a new list. We count how many time i element(i is a element in set(l)) occurs in native list l (l = [2, 3, 7, 2, 3, 8, 7, 3]). And in [i]*l.count(i) i become l.count(i) times in the new list. List-comprehension method gets the all values after iterations are done and pack it in a list and returns list. * sign at the beginning is for unpacking the values in the returned list. And finally *print()* keyword sep='\n' put a '\n' after each elements in the unpacked list. Without it this could have been done like:

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

Upvotes: 2

anjaneyulubatta505
anjaneyulubatta505

Reputation: 11665

Try this

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

Output:

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

Upvotes: 4

Vineeth Sai
Vineeth Sai

Reputation: 3447

Here's a short way of doing it by using 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()] 

Outputs:

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

Upvotes: 3

slider
slider

Reputation: 12990

One way to do this is to use a simple 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]]

Upvotes: 3

qxang
qxang

Reputation: 318

I think you may try collections.Counter, and get different keys and its count in this list.

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} 

Upvotes: 2

Venkatachalam
Venkatachalam

Reputation: 16966

Doing this operation in Numpy array would be efficient

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

Output:

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

Upvotes: 2

Related Questions