Shuffle a list items among dissimilar items - python

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]

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.

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

Related

Python: 3rd level nested list comprehension not acting as expected

I am trying to get all possible permutations of length 1, 2 and 3 for the charactes "a", "b" and "c"
from itertools import permutations
a = ['a','b', 'c']
perm1 = permutations(a, 1)
perm2 = permutations(a, 2)
perm3 = permutations(a, 3)
p_list = []
p_list.extend(list(perm1))
p_list.extend(list(perm2))
p_list.extend(list(perm3))
str = [[j for j in i] for i in p_list]
print(str[3])
At this point things are expected
When I modify the str = line to this str = [[[''.join(k) for k in j] for j in i] for i in p_list] I would expect to get a list of strings where each permutation is a string with no commas. e.g. ["abc", "a", "b", "c"] etc. but instead I get a list of lists.
First thing: please don't set str as variable.
Below I copied your code, commenting what p_list looks like.
from itertools import permutations
a = ['a','b', 'c']
perm1 = permutations(a, 1)
perm2 = permutations(a, 2)
perm3 = permutations(a, 3)
p_list = []
p_list.extend(list(perm1))
p_list.extend(list(perm2))
p_list.extend(list(perm3))
# p_list = [('a',), ('b',), ('c',), ('a', 'b'), ('a', 'c'), ('b', 'a'), ('b', 'c'), ('c', 'a'), ('c', 'b'), ('a', 'b', 'c'), ('a', 'c', 'b'), ('b', 'a', 'c'), ('b', 'c', 'a'), ('c', 'a', 'b'), ('c', 'b', 'a')]
As you can see, your data structure is not 3rd level: it is only a list of tuples. Now I think it becomes clear that your list comprehension is just iterating over each element inside the tuples, not joining them like:
result = [''.join(n) for n in p_list]
# result = ['a', 'b', 'c', 'ab', 'ac', 'ba', 'bc', 'ca', 'cb', 'abc', 'acb', 'bac', 'bca', 'cab', 'cba']

Python Itertools Add List for Every Combination

I need to create every combination for list1, but add list2 to every combination of list1.
For example, this creates a combination for every value for list1:
list1 = ["a", "b" , "c"]
list2 = ["d", "e"]
list(itertools.combinations(list1, 2))
[('a', 'b'), ('a', 'c'), ('b', 'c')]
But I would like the result to be:
[('a', 'b', 'd', 'e'), ('a', 'c'', d', 'e'), ('b', 'c', 'd', 'e')]
I have tried these common approaches, but am getting undesired results:
list1 = ["a", "b" , "c"]
list2 = ["d", "e"]
print(list(itertools.combinations(list1, 2)).extend(list2))
None
print(list(itertools.combinations(list1, 2)) + list2)
[('a', 'b'), ('a', 'c'), ('b', 'c'), 'd', 'e']
print(list(itertools.combinations(list1, 2) + list2))
TypeError: unsupported operand type(s) for +: 'itertools.combinations' and 'list'
Any help would be appreciated. Thanks.
You can first generate a tuple of size 2 combinations for each list separately, then compute the cartesian product of those to combination lists:
import itertools
list1 = ["a", "b" , "c"]
list2 = ["d", "e"]
iter1 = itertools.combinations(list1, 2)
iter2 = itertools.combinations(list2, 2)
# If you want to add a subset of size 2 from list 2:
product = itertools.product(iter1, iter2)
answer = list(map(lambda x: (*x[0], *x[1]), product))
# [('a', 'b', 'd', 'e'), ('a', 'c', 'd', 'e'), ('b', 'c', 'd', 'e')]
However, if you want to add all elements of list2 you can use:
import itertools
list1 = ["a", "b" , "c"]
list2 = ["d", "e", "f"]
iter1 = itertools.combinations(list1, 2)
# If you want to add all elements of list2
product = itertools.product(iter1, [list2])
answer = list(map(lambda x: (*x[0], *x[1]), product))
# [('a', 'b', 'd', 'e', 'f'), ('a', 'c', 'd', 'e', 'f'), ('b', 'c', 'd', 'e', 'f')]

python get groups of combinations that each member appear only once

I'm trying to get groups of permutations/combinations (r=2) that each member appear only once
I used python 'combinations' package to have the combinations.
For example: the members are: a,b,c,d.
The combinations are: [a,b],[a,c],[a,d],[b,c],[b,d]...
My desired output is:
[ {[a,b],[c,d]},{[a,c],[b,d]},{[a,d],[b,c]}...]
I would like to know what is the terminology for that case and if there is already implementation for that.
Thanks.
Here's a way to do it:
from itertools import combinations, chain
l = ['a','b','c','d']
c = list(combinations(l,2))
[set(i) for i in list(combinations(c,2)) if (len(set(l) & set(chain(*i))) == len(l))]
[{('a', 'b'), ('c', 'd')}, {('a', 'c'), ('b', 'd')}, {('a', 'd'), ('b', 'c')}]
Explanation
You can use itertools.combinations twice, in order to get all the 2 tuple combinations from:
list(combinations(l,2))
[('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
And select only those whose set of elements intersect with that of the original list, len(set(l) & set(chain(*i))) == len(l)) for every possible combination.
You can find the permutations up to r and then filter the results:
def combinations(d, d1, r, _c = [], _start=[]):
if len([i for b in _c for i in b]) == len(d1):
yield _c
else:
for i in d:
if i not in _start:
if len(_start+[i]) < r:
yield from combinations(d, d1, r, _c, _start=_start+[i])
else:
_d = sorted(_start+[i])
yield from combinations([i for i in d if i not in _d], d1,r, _c+[_d], [])
data = ['a', 'b', 'c', 'd']
_r = list(combinations(data, data, 2))
new_d = [a for i, a in enumerate(_r) if a not in _r[:i]]
Output:
[[['a', 'b'], ['c', 'd']], [['a', 'c'], ['b', 'd']], [['a', 'd'], ['b', 'c']], [['b', 'c'], ['a', 'd']], [['b', 'd'], ['a', 'c']], [['c', 'd'], ['a', 'b']]]

What is the difference between these two List in Python?

I have two Lists in my program list1 and list2 which looks like the following:
list1 = ['ABC',
'ABD',
'ABE',
'ABF',
'ABG',
'ABH',
'ABI',
...]
list2 = [('A', 'B', 'C'),
('A', 'B', 'D'),
('A', 'B', 'E'),
('A', 'B', 'F'),
('A', 'B', 'G'),
('A', 'B', 'I'),
...]
Both the Lists are 2D because they return the same result on the same operation.
list1[0][1] returns 'B'
list2[0][1] also returns 'B'
What is the difference between list1 and list2 if they return the same result? How do I convert list2 in the format of list1?
Thank you.
The first list is list of strings and second list is list of tuples containing strings.
To convert list2 to list1 you can use:
list2 = [('A', 'B', 'C'),
('A', 'B', 'D'),
('A', 'B', 'E'),
('A', 'B', 'F'),
('A', 'B', 'G'),
('A', 'B', 'I'),]
new_list = [''.join(v) for v in list2]
print(new_list)
Output:
['ABC', 'ABD', 'ABE', 'ABF', 'ABG', 'ABI']

Python create many-to-many relationships from a list

I have a list, say terms = ['A', 'B', 'C', 'D']
Which is the best way to create a list-of-lists or list-of-tuples of many-to-many relationships like this;
[['A','B'],['A','C'],['A','D'],['B','C'],['B','D'],['C','D']]
Using itertools.combinations():
from itertools import combinations
list(combinations(terms, r=2))
Demo:
>>> from itertools import combinations
>>> terms = ['A', 'B', 'C', 'D']
>>> list(combinations(terms, r=2))
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')]
These are tuples, not lists, but that's easily remedied if that is a problem:
>>> map(list, combinations(terms, r=2))
[['A', 'B'], ['A', 'C'], ['A', 'D'], ['B', 'C'], ['B', 'D'], ['C', 'D']]

Categories