'Shuffle a list items among dissimilar items

How to shuffle list items keeping the similar items unshuffled? E.g. for the list 'L', I want to shuffle among the unique items.

L=[a,a,b,b,c,c,d,d]

For the above list, I want to get

shuffled_L=[c,c,a,a,d,d,b,b]


Solution 1:[1]

Group into tuples, shuffle the tuples, flatten the list again:

>>> from itertools import groupby, chain
>>> from random import shuffle
>>> L = ["a", "a", "b", "b", "c", "c", "d", "d"]
>>> L_ = [tuple(v) for _, v in groupby(L)]
[('a', 'a'), ('b', 'b'), ('c', 'c'), ('d', 'd')]
>>> random.shuffle(L_)
[('b', 'b'), ('a', 'a'), ('d', 'd'), ('c', 'c')]
>>> list(chain.from_iterable(L_))
['b', 'b', 'a', 'a', 'd', 'd', 'c', 'c']

This assumes the original L is already sorted. If it isn't, sort it before the groupby step.

Solution 2:[2]

applying @suddents_appearence method from the comments

>>> import random
>>> import itertools
>>> from collections import Counter
>>> L=["a","a","b","b","c","c","d","d"]
>>> count=Counter(L)
>>> sample=random.sample(sorted(count),len(count))
>>> _shuffled_L=list(map(lambda x:[x]*count.get(x),sample))
>>> shuffled_L=list(itertools.chain.from_iterable(_shuffled_L))
>>> shuffled_L
['d', 'd', 'b', 'b', 'a', 'a', 'c', 'c']

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 deceze
Solution 2