Python Exercise Tuples, set and list - python

can you please help me? I tried everything, but I'm lost.
From the data I need to get this list of tuples.
The idea is to organize this list in the best readable way.
From the data, if I found a 1, I need to make a tuple with the value and a list with the letters from the second column, so It would appear in order, like ['E', 'B', 'E'].
This is the data:
[(1, 'E'),
(2, 'A'),
(5, 'B'),
(3, 'A'),
(6, 'C'),
(7, 'A'),
(9, 'A'),
(1, 'B'),
(2, 'E'),
(3, 'B'),
(7, 'C'),
(5, 'C'),
(3, 'D'),
(8, 'E'),
(9, 'B'),
(8, 'D'),
(3, 'E'),
(5, 'D'),
(8, 'E'),
(9, 'E'),
(7, 'E'),
(3, 'E'),
(5, 'D'),
(9, 'A'),
(4, 'E'),
(6, 'E'),
(8, 'A'),
(5, 'E'),
(6, 'A'),
(0, 'C'),
(9, 'A'),
(3, 'D'),
(5, 'E'),
(4, 'B'),
(6, 'B'),
(7, 'D'),
(8, 'B'),
(9, 'C'),
(1, 'E'),
(5, 'E')]
# Result/
# ('0', ['C'])
# ('1', ['E', 'B', 'E'])
# ('2', ['A', 'E'])
# ('3', ['A', 'B', 'D', 'E', 'E', 'D'])
# ('4', ['E', 'B'])
# ('5', ['B', 'C', 'D', 'D', 'E', 'E', 'E'])
# ('6', ['C', 'E', 'A', 'B'])
# ('7', ['A', 'C', 'E', 'D'])
# ('8', ['E', 'D', 'E', 'A', 'B'])
# ('9', ['A', 'B', 'E', 'A', 'A', 'C'])

You can use defaultdict:
from collections import defaultdict
data = [(1, 'E'), (2, 'A'), (5, 'B'), (3, 'A'), (6, 'C'), (7, 'A'), (9, 'A'), (1, 'B'),
(2, 'E'), (3, 'B'), (7, 'C'), (5, 'C'), (3, 'D'), (8, 'E'), (9, 'B'), (8, 'D'),
(3, 'E'), (5, 'D'), (8, 'E'), (9, 'E'), (7, 'E'), (3, 'E'), (5, 'D'), (9, 'A'),
(4, 'E'), (6, 'E'), (8, 'A'), (5, 'E'), (6, 'A'), (0, 'C'), (9, 'A'), (3, 'D'),
(5, 'E'), (4, 'B'), (6, 'B'), (7, 'D'), (8, 'B'), (9, 'C'), (1, 'E'), (5, 'E')]
d = defaultdict(list)
for x, y in data:
d[str(x)].append(y)
output = sorted(d.items())
print(output)
Output:
[('0', ['C']), ('1', ['E', 'B', 'E']), ('2', ['A', 'E']), ('3', ['A', 'B', 'D', 'E', 'E', 'D']), ('4', ['E', 'B']), ('5', ['B', 'C', 'D', 'D', 'E', 'E', 'E']), ('6', ['C', 'E', 'A', 'B']), ('7', ['A', 'C', 'E', 'D']), ('8', ['E', 'D', 'E', 'A', 'B']), ('9', ['A', 'B', 'E', 'A', 'A', 'C '])]
Alternatively, if you know the keys a priori, you can set the keys in advance. This won't need defaultdict nor sorted (the latter in python 3.7+).
d = {str(k): [] for k in range(10)}
for x, y in data:
d[str(x)].append(y)
output = list(d.items())

Related

n-fold Cartesian product on a single list in Python [duplicate]

This question already has answers here:
Generating permutations with repetitions
(6 answers)
Closed 8 months ago.
How to compute the n-fold Cartesian product on a list, that is, A × ... × A (n times), in an elegant (concise) way in Python?
Examples:
>>> l = ["a", "b", "c"]
>>> cart_prod(l, 0)
[]
>>> cart_prod(l, 1)
[('a',), ('b',), ('c',)]
>>> cart_prod(l, 2)
[('a', 'a'), ('a', 'b'), ('a', 'c'), ('b', 'a'), ('b', 'b'), ('b', 'c'), ('c', 'a'), ('c', 'b'), ('c', 'c')]
>>> cart_prod(l, 3)
[('a', 'a', 'a'), ('a', 'a', 'b'), ('a', 'a', 'c'), ('a', 'b', 'a'), ('a', 'b', 'b'), ('a', 'b', 'c'), ('a', 'c', 'a'), ('a', 'c', 'b'), ('a', 'c', 'c'),
('b', 'a', 'a'), ('b', 'a', 'b'), ('b', 'a', 'c'), ('b', 'b', 'a'), ('b', 'b', 'b'), ('b', 'b', 'c'), ('b', 'c', 'a'), ('b', 'c', 'b'), ('b', 'c', 'c'),
('c', 'a', 'a'), ('c', 'a', 'b'), ('c', 'a', 'c'), ('c', 'b', 'a'), ('c', 'b', 'b'), ('c', 'b', 'c'), ('c', 'c', 'a'), ('c', 'c', 'b'), ('c', 'c', 'c')]
I came up with the following iterative solution:
def cart_prod(l, n):
if n == 0:
return [] # compute the result for n = 0
# preliminarily, create a list of lists instead of a list of tuples
res = [[x] for x in l] # initialize list with singleton tuples (n = 1)
for i in range(n-1):
res = [r + [x] for r in res for x in l] # concatenate each n-1 tuple with each element from a
res = [tuple(el) for el in res] # turn the list of lists into a list of tuples
return res
This code does the job, but is there a shorter, possibly one-liner definition, maybe a nested list comprehension or a lambda expression? I am interested in more compact solutions, not necessarily more readable ones.
This question is not a duplicate of Get the cartesian product of a series of lists?. I do not want the Cartesian product of a series of lists crossed with each other. I want the Cartesian product of a single list crossed n-times with itself, where n is a parameter given to the function.
itertools.product takes a keyword argument to indicate the given arguments should be repeated.
>>> from itertools import product
>>> list(product([1,2], repeat=0))
[()]
>>> list(product([1,2], repeat=1))
[(1,), (2,)]
>>> list(product([1,2], repeat=2))
[(1, 1), (1, 2), (2, 1), (2, 2)]
This works with multiple iterables as well.
# Equivalent to list(product([1,2], ['a', 'b'], [1,2], ['a', 'b']))
>>> list(product([1,2], ['a', 'b'], repeat=2))
[(1, 'a', 1, 'a'), (1, 'a', 1, 'b'), (1, 'a', 2, 'a'), (1, 'a', 2, 'b'), (1, 'b', 1, 'a'), (1, 'b', 1, 'b'), (1, 'b', 2, 'a'), (1, 'b', 2, 'b'), (2, 'a', 1, 'a'), (2, 'a', 1, 'b'), (2, 'a', 2, 'a'), (2, 'a', 2, 'b'), (2, 'b', 1, 'a'), (2, 'b', 1, 'b'), (2, 'b', 2, 'a'), (2, 'b', 2, 'b')]

How to efficiently search a list in python

I have a dictionary with only 4 keys (mydictionary) and a list (mynodes) as follows.
mydictionary = {0: {('B', 'E', 'G'), ('A', 'E', 'G'), ('A', 'E', 'F'), ('A', 'D', 'F'), ('C', 'D', 'F'), ('C', 'E', 'F'), ('A', 'D', 'G'), ('C', 'D', 'G'), ('C', 'E', 'G'), ('B', 'E', 'F')},
1: {('A', 'C', 'G'), ('E', 'F', 'G'), ('D', 'E', 'F'), ('A', 'F', 'G'), ('A', 'B', 'G'), ('B', 'D', 'F'), ('C', 'F', 'G'), ('A', 'C', 'E'), ('D', 'E', 'G'), ('B', 'F', 'G'), ('B', 'C', 'G'), ('A', 'C', 'D'), ('A', 'B', 'F'), ('B', 'D', 'G'), ('B', 'C', 'F'), ('A', 'D', 'E'), ('C', 'D', 'E'), ('A', 'C', 'F'), ('A', 'B', 'E'), ('B', 'C', 'E'), ('D', 'F', 'G')},
2: {('B', 'D', 'E'), ('A', 'B', 'D'), ('B', 'C', 'D')},
3: {('A', 'B', 'C')}}
mynodes = ['E', 'D', 'G', 'F', 'B', 'A', 'C']
I am checking how many times each node in mynodes list is in each key of mydictionary. For example, consider the above dictionary and list.
The output should be;
{'E': [(0, 6), (1, 8), (2, 1), (3, 0)],
'D': [(0, 4), (1, 8), (2, 3), (3, 0)],
'G': [(0, 5), (1, 10), (2, 0), (3, 0)],
'F': [(0, 5), (1, 10), (2, 0), (3, 0)],
'B': [(0, 2), (1, 9), (2, 3), (3, 1)],
'A': [(0, 4), (1, 9), (2, 1), (3, 1)],
'C': [(0, 4), (1, 9), (2, 1), (3, 1)]}
For example, consider E. It appears 6 times in 0 key, 8 times in 1 key, 2 times in 2 key and 0 times in 3 key.
My current code is as follows.
triad_class_for_nodes = {}
for node in mynodes:
temp_list = []
for key, value in mydictionary.items():
temp_counting = 0
for triad in value:
#print(triad[0])
if node in triad:
temp_counting = temp_counting + 1
temp_list.append(tuple((key, temp_counting)))
triad_class_for_nodes.update({node: temp_list})
print(triad_class_for_nodes)
This works fine with the small dictionary values.
However, in my real dataset, I have millions of tuples in the value list for each of my 4 keys in my dictionary. Hence, my existing code is really inefficient and takes days to run.
When I search on how to make this more efficient I came accross this question (Fastest way to search a list in python), which suggests to make the list of values to a set. I tried this as well. However, it also takes days to run.
I am just wondering if there is a more efficient way of doing this in python. I am happy to transform my existing data formats into different structures (such as pandas dataframe) to make things more efficient.
A small sample of mydictionary and mynodes is attached below for testing purposes. https://drive.google.com/drive/folders/15Faa78xlNAYLPvqS3cKM1v8bV1HQzW2W?usp=sharing
mydictionary: see triads.txt
with open("triads.txt", "r") as file:
mydictionary = ast.literal_eval(file.read)
mynodes: see nodes.txt
with open("nodes.txt", "r") as file:
mynodes = ast.literal_eval(file.read)
I am happy to provide more details if needed.
Since you tag pandas, first we need convert your dict to pandas dataframe , then we stack it , and using crosstab
s=pd.DataFrame.from_dict(mydictionary,'index').stack()
s = pd.DataFrame(s.values.tolist(), index=s.index).stack()
pd.crosstab(s.index.get_level_values(0),s)
col_0 A B C D E F G
row_0
0 4 2 4 4 6 5 5
1 9 9 9 8 8 10 10
2 1 3 1 3 1 0 0
3 1 1 1 0 0 0 0
Update
s=pd.crosstab(s.index.get_level_values(0), s).stack().reset_index()
s[['row_0',0]].apply(tuple,1).groupby(s['col_0']).agg(list).to_dict()
If you're not using pandas, you could do this with Counter from collections:
from collections import Counter,defaultdict
from itertools import product
counts = Counter((c,k) for k,v in mydictionary.items() for t in v for c in t )
result = defaultdict(list)
for c,k in product(mynodes,mydictionary):
result[c].append((k,counts[(c,k)]))
print(result)
{'E': [(0, 6), (1, 8), (2, 1), (3, 0)],
'D': [(0, 4), (1, 8), (2, 3), (3, 0)],
'G': [(0, 5), (1, 10), (2, 0), (3, 0)],
'F': [(0, 5), (1, 10), (2, 0), (3, 0)],
'B': [(0, 2), (1, 9), (2, 3), (3, 1)],
'A': [(0, 4), (1, 9), (2, 1), (3, 1)],
'C': [(0, 4), (1, 9), (2, 1), (3, 1)]}
Counter will manage counting instances for each combination of mydictionary key and node. You can then use these counts to create the expected output.
EDIT Expanded counts line:
counts = Counter() # initialize Counter() object
for key,tupleSet in mydictionary.items(): # loop through dictionary
for tupl in tupleSet: # loop through tuple set of each key
for node in tupl: # loop through node character in each tuple
counts[(node,key]] += 1 # count 1 node/key pair

Generate all possible comparisons 3 v 3 in a group of 6

I have 6 samples and I would like to generate all possible 3v3 comparisons using python.
So far I've managed to use the combinations function to generate all possible groups of 3. But I fail to generate the match comparisons (if I have CM26 in the first group I don't want to compare it against a group of 3 with it).
def combinations(iterable, r):
# combinations('ABCD', 2) --> AB AC AD BC BD CD
# combinations(range(4), 3) --> 012 013 023 123
pool = tuple(iterable)
n = len(pool)
if r > n:
return
indices = range(r)
yield tuple(pool[i] for i in indices)
while True:
for i in reversed(range(r)):
if indices[i] != i + n - r:
break
else:
return
indices[i] += 1
for j in range(i+1, r):
indices[j] = indices[j-1] + 1
yield tuple(pool[i] for i in indices)
columns = {'CM19':1,'CM20':2,'CM21':3,'CM23':5,'CM25':7,'CM26':8}
for i in combinations(columns,3):
print i
('CM26', 'CM19', 'CM25') ('CM26', 'CM19', 'CM23') ('CM26', 'CM19',
'CM20') ('CM26', 'CM19', 'CM21') ('CM26', 'CM25', 'CM23') ('CM26',
'CM25', 'CM20') ('CM26', 'CM25', 'CM21') ('CM26', 'CM23', 'CM20')
('CM26', 'CM23', 'CM21') ('CM26', 'CM20', 'CM21') ('CM19', 'CM25',
'CM23') ('CM19', 'CM25', 'CM20') ('CM19', 'CM25', 'CM21') ('CM19',
'CM23', 'CM20') ('CM19', 'CM23', 'CM21') ('CM19', 'CM20', 'CM21')
('CM25', 'CM23', 'CM20') ('CM25', 'CM23', 'CM21') ('CM25', 'CM20',
'CM21') ('CM23', 'CM20', 'CM21')
I would like to compare each group to the others but eliminating repetition.
Always pick a triple with the first element present, and use the complement of the set for the other triple.
Here's code.
import itertools
def three_vs_three(xs):
xset = set(xs)
for i1, i2 in itertools.combinations(xs[1:], 2):
triple = set([xs[0], i1, i2])
yield sorted(triple), sorted(xset - triple)
things = ['CM%d' % x for x in 19, 20, 21, 23, 25, 26]
print list(three_vs_three(things))
The two tricks to solving this are the following:
You can use itertools.permutations with the second parameter of 3 to generate sets of 3 elements
You can use set.difference to figure out the compliment for any generated tuple in Step 1
group = set(['A','B','C','D','E','F'])
import itertools
comparisons = [(tuple(i),tuple(set.difference(group,i))) for i in itertools.permutations(group,3)]
Result
[(('A', 'C', 'B'), ('E', 'D', 'F')),
(('A', 'C', 'E'), ('B', 'D', 'F')),
(('A', 'C', 'D'), ('B', 'E', 'F')),
(('A', 'C', 'F'), ('B', 'E', 'D')),
(('A', 'B', 'C'), ('E', 'D', 'F')),
(('A', 'B', 'E'), ('C', 'D', 'F')),
(('A', 'B', 'D'), ('C', 'E', 'F')),
(('A', 'B', 'F'), ('C', 'E', 'D')),
(('A', 'E', 'C'), ('B', 'D', 'F')),
(('A', 'E', 'B'), ('C', 'D', 'F')),
(('A', 'E', 'D'), ('C', 'B', 'F')),
(('A', 'E', 'F'), ('C', 'B', 'D')),
(('A', 'D', 'C'), ('B', 'E', 'F')),
(('A', 'D', 'B'), ('C', 'E', 'F')),
(('A', 'D', 'E'), ('C', 'B', 'F')),
(('A', 'D', 'F'), ('C', 'B', 'E')),
(('A', 'F', 'C'), ('B', 'E', 'D')),
(('A', 'F', 'B'), ('C', 'E', 'D')),
(('A', 'F', 'E'), ('C', 'B', 'D')),
(('A', 'F', 'D'), ('C', 'B', 'E')),
(('C', 'A', 'B'), ('E', 'D', 'F')),
(('C', 'A', 'E'), ('B', 'D', 'F')),
(('C', 'A', 'D'), ('B', 'E', 'F')),
(('C', 'A', 'F'), ('B', 'E', 'D')),
(('C', 'B', 'A'), ('E', 'D', 'F')),
(('C', 'B', 'E'), ('A', 'D', 'F')),
(('C', 'B', 'D'), ('A', 'E', 'F')),
(('C', 'B', 'F'), ('A', 'E', 'D')),
(('C', 'E', 'A'), ('B', 'D', 'F')),
(('C', 'E', 'B'), ('A', 'D', 'F')),
(('C', 'E', 'D'), ('A', 'B', 'F')),
(('C', 'E', 'F'), ('A', 'B', 'D')),
(('C', 'D', 'A'), ('B', 'E', 'F')),
(('C', 'D', 'B'), ('A', 'E', 'F')),
(('C', 'D', 'E'), ('A', 'B', 'F')),
(('C', 'D', 'F'), ('A', 'B', 'E')),
(('C', 'F', 'A'), ('B', 'E', 'D')),
(('C', 'F', 'B'), ('A', 'E', 'D')),
(('C', 'F', 'E'), ('A', 'B', 'D')),
(('C', 'F', 'D'), ('A', 'B', 'E')),
(('B', 'A', 'C'), ('E', 'D', 'F')),
(('B', 'A', 'E'), ('C', 'D', 'F')),
(('B', 'A', 'D'), ('C', 'E', 'F')),
(('B', 'A', 'F'), ('C', 'E', 'D')),
(('B', 'C', 'A'), ('E', 'D', 'F')),
(('B', 'C', 'E'), ('A', 'D', 'F')),
(('B', 'C', 'D'), ('A', 'E', 'F')),
(('B', 'C', 'F'), ('A', 'E', 'D')),
(('B', 'E', 'A'), ('C', 'D', 'F')),
(('B', 'E', 'C'), ('A', 'D', 'F')),
(('B', 'E', 'D'), ('A', 'C', 'F')),
(('B', 'E', 'F'), ('A', 'C', 'D')),
(('B', 'D', 'A'), ('C', 'E', 'F')),
(('B', 'D', 'C'), ('A', 'E', 'F')),
(('B', 'D', 'E'), ('A', 'C', 'F')),
(('B', 'D', 'F'), ('A', 'C', 'E')),
(('B', 'F', 'A'), ('C', 'E', 'D')),
(('B', 'F', 'C'), ('A', 'E', 'D')),
(('B', 'F', 'E'), ('A', 'C', 'D')),
(('B', 'F', 'D'), ('A', 'C', 'E')),
(('E', 'A', 'C'), ('B', 'D', 'F')),
(('E', 'A', 'B'), ('C', 'D', 'F')),
(('E', 'A', 'D'), ('C', 'B', 'F')),
(('E', 'A', 'F'), ('C', 'B', 'D')),
(('E', 'C', 'A'), ('B', 'D', 'F')),
(('E', 'C', 'B'), ('A', 'D', 'F')),
(('E', 'C', 'D'), ('A', 'B', 'F')),
(('E', 'C', 'F'), ('A', 'B', 'D')),
(('E', 'B', 'A'), ('C', 'D', 'F')),
(('E', 'B', 'C'), ('A', 'D', 'F')),
(('E', 'B', 'D'), ('A', 'C', 'F')),
(('E', 'B', 'F'), ('A', 'C', 'D')),
(('E', 'D', 'A'), ('C', 'B', 'F')),
(('E', 'D', 'C'), ('A', 'B', 'F')),
(('E', 'D', 'B'), ('A', 'C', 'F')),
(('E', 'D', 'F'), ('A', 'C', 'B')),
(('E', 'F', 'A'), ('C', 'B', 'D')),
(('E', 'F', 'C'), ('A', 'B', 'D')),
(('E', 'F', 'B'), ('A', 'C', 'D')),
(('E', 'F', 'D'), ('A', 'C', 'B')),
(('D', 'A', 'C'), ('B', 'E', 'F')),
(('D', 'A', 'B'), ('C', 'E', 'F')),
(('D', 'A', 'E'), ('C', 'B', 'F')),
(('D', 'A', 'F'), ('C', 'B', 'E')),
(('D', 'C', 'A'), ('B', 'E', 'F')),
(('D', 'C', 'B'), ('A', 'E', 'F')),
(('D', 'C', 'E'), ('A', 'B', 'F')),
(('D', 'C', 'F'), ('A', 'B', 'E')),
(('D', 'B', 'A'), ('C', 'E', 'F')),
(('D', 'B', 'C'), ('A', 'E', 'F')),
(('D', 'B', 'E'), ('A', 'C', 'F')),
(('D', 'B', 'F'), ('A', 'C', 'E')),
(('D', 'E', 'A'), ('C', 'B', 'F')),
(('D', 'E', 'C'), ('A', 'B', 'F')),
(('D', 'E', 'B'), ('A', 'C', 'F')),
(('D', 'E', 'F'), ('A', 'C', 'B')),
(('D', 'F', 'A'), ('C', 'B', 'E')),
(('D', 'F', 'C'), ('A', 'B', 'E')),
(('D', 'F', 'B'), ('A', 'C', 'E')),
(('D', 'F', 'E'), ('A', 'C', 'B')),
(('F', 'A', 'C'), ('B', 'E', 'D')),
(('F', 'A', 'B'), ('C', 'E', 'D')),
(('F', 'A', 'E'), ('C', 'B', 'D')),
(('F', 'A', 'D'), ('C', 'B', 'E')),
(('F', 'C', 'A'), ('B', 'E', 'D')),
(('F', 'C', 'B'), ('A', 'E', 'D')),
(('F', 'C', 'E'), ('A', 'B', 'D')),
(('F', 'C', 'D'), ('A', 'B', 'E')),
(('F', 'B', 'A'), ('C', 'E', 'D')),
(('F', 'B', 'C'), ('A', 'E', 'D')),
(('F', 'B', 'E'), ('A', 'C', 'D')),
(('F', 'B', 'D'), ('A', 'C', 'E')),
(('F', 'E', 'A'), ('C', 'B', 'D')),
(('F', 'E', 'C'), ('A', 'B', 'D')),
(('F', 'E', 'B'), ('A', 'C', 'D')),
(('F', 'E', 'D'), ('A', 'C', 'B')),
(('F', 'D', 'A'), ('C', 'B', 'E')),
(('F', 'D', 'C'), ('A', 'B', 'E')),
(('F', 'D', 'B'), ('A', 'C', 'E')),
(('F', 'D', 'E'), ('A', 'C', 'B'))]

Permutation with redundant overlaps? Python

I used itertools to run a permutation on a list that I have.
mylist = [a, b, c, d, e, f]
mypermutations = itertools.permutations(mylist,2)
mypermutations_list = list(mypermutations)
print mypermutations_list
prints:
[(a, b), (a, c), (a, d)...]
However, the permutation list doesn't include (a, a), (b, b), etc. I recognize that's probably because most people don't want such redundant pairings. However, I would like to include such pairings as a control for the program I'm writing.
Is there a way to run a permutation and get these combinations? I have no idea what to use instead of permutations.
You want itertools.product instead:
>>> import itertools
>>> mylist = ['a', 'b', 'c', 'd', 'e', 'f']
>>> list(itertools.product(mylist, repeat=2))
[('a', 'a'), ('a', 'b'), ('a', 'c'), ...]
You're looking for itertools.product, it returns the Cartesian product of the iterable:
>>> from itertools import product
>>> list(product('abcdef', repeat=2))
[('a', 'a'), ('a', 'b'), ('a', 'c'), ('a', 'd'), ('a', 'e'), ('a', 'f'), ('b', 'a'), ('b', 'b'), ('b', 'c'), ('b', 'd'), ('b', 'e'), ('b', 'f'), ('c', 'a'), ('c', 'b'), ('c', 'c'), ('c', 'd'), ('c', 'e'), ('c', 'f'), ('d', 'a'), ('d', 'b'), ('d', 'c'), ('d', 'd'), ('d', 'e'), ('d', 'f'), ('e', 'a'), ('e', 'b'), ('e', 'c'), ('e', 'd'), ('e', 'e'), ('e', 'f'), ('f', 'a'), ('f', 'b'), ('f', 'c'), ('f', 'd'), ('f', 'e'), ('f', 'f')]

Python permutations of both sequence and subsequences

Question: How do I implement double_permutations(s) below?
>>> s = [('a', 'b'), ('c', 'd'), ('e', 'f')]
>>> for answer in double_permutation(s):
... print(answer) # in some order
[('a', 'b'), ('c', 'd'), ('e', 'f')]
[('a', 'b'), ('d', 'c'), ('e', 'f')]
[('a', 'b'), ('c', 'd'), ('f', 'e')]
[('a', 'b'), ('d', 'c'), ('f', 'e')]
[('a', 'b'), ('e', 'f'), ('c', 'd')]
[('a', 'b'), ('f', 'e'), ('c', 'd')]
[('a', 'b'), ('e', 'f'), ('d', 'c')]
[('a', 'b'), ('f', 'e'), ('d', 'c')]
What I've tried (breaks down once the outer list is longer than 3 elements)
from itertools import permutations
def double_permutation(l):
def double_permutation_recur(s, r):
if not r:
yield s
else:
for permutation in permutations(r):
s1 = s + [permutation[0]]
s2 = s + [(permutation[0][1], permutation[0][0])]
for perm1 in double_permutation_recur(s1, permutation[1:]):
yield perm1
for perm2 in double_permutation_recur(s2, permutation[1:]):
yield perm2
return double_permutation_recur([l[0]], l[1:])
This should yield double_factorial(n-1) answers for a list of length n. This works up through n = 3, but breaks down at n = 4 (which yields 96 instead of 48 answers).
You can build this up from the primitives in the itertools module
import itertools
s = [('a', 'b'), ('c', 'd'), ('e', 'f')]
Is this what you're describing?
def permute(it):
return itertools.product(*(itertools.permutations(i) for i in it))
>>> for i in permute(s):
... print i
(('a', 'b'), ('c', 'd'), ('e', 'f'))
(('a', 'b'), ('c', 'd'), ('f', 'e'))
(('a', 'b'), ('d', 'c'), ('e', 'f'))
(('a', 'b'), ('d', 'c'), ('f', 'e'))
(('b', 'a'), ('c', 'd'), ('e', 'f'))
(('b', 'a'), ('c', 'd'), ('f', 'e'))
(('b', 'a'), ('d', 'c'), ('e', 'f'))
(('b', 'a'), ('d', 'c'), ('f', 'e'))
Or do you want:
def permute2(it):
return itertools.chain.from_iterable(
permute(p)
for p in itertools.permutations(it)
)
>>> for i in permute2(s):
... print i
(('a', 'b'), ('c', 'd'), ('e', 'f'))
(('a', 'b'), ('c', 'd'), ('f', 'e'))
(('a', 'b'), ('d', 'c'), ('e', 'f'))
(('a', 'b'), ('d', 'c'), ('f', 'e'))
(('b', 'a'), ('c', 'd'), ('e', 'f'))
(('b', 'a'), ('c', 'd'), ('f', 'e'))
(('b', 'a'), ('d', 'c'), ('e', 'f'))
(('b', 'a'), ('d', 'c'), ('f', 'e'))
(('a', 'b'), ('e', 'f'), ('c', 'd'))
(('a', 'b'), ('e', 'f'), ('d', 'c'))
(('a', 'b'), ('f', 'e'), ('c', 'd'))
(('a', 'b'), ('f', 'e'), ('d', 'c'))
(('b', 'a'), ('e', 'f'), ('c', 'd'))
(('b', 'a'), ('e', 'f'), ('d', 'c'))
(('b', 'a'), ('f', 'e'), ('c', 'd'))
(('b', 'a'), ('f', 'e'), ('d', 'c'))
(('c', 'd'), ('a', 'b'), ('e', 'f'))
(('c', 'd'), ('a', 'b'), ('f', 'e'))
(('c', 'd'), ('b', 'a'), ('e', 'f'))
(('c', 'd'), ('b', 'a'), ('f', 'e'))
(('d', 'c'), ('a', 'b'), ('e', 'f'))
(('d', 'c'), ('a', 'b'), ('f', 'e'))
(('d', 'c'), ('b', 'a'), ('e', 'f'))
(('d', 'c'), ('b', 'a'), ('f', 'e'))
(('c', 'd'), ('e', 'f'), ('a', 'b'))
(('c', 'd'), ('e', 'f'), ('b', 'a'))
(('c', 'd'), ('f', 'e'), ('a', 'b'))
(('c', 'd'), ('f', 'e'), ('b', 'a'))
(('d', 'c'), ('e', 'f'), ('a', 'b'))
(('d', 'c'), ('e', 'f'), ('b', 'a'))
(('d', 'c'), ('f', 'e'), ('a', 'b'))
(('d', 'c'), ('f', 'e'), ('b', 'a'))
(('e', 'f'), ('a', 'b'), ('c', 'd'))
(('e', 'f'), ('a', 'b'), ('d', 'c'))
(('e', 'f'), ('b', 'a'), ('c', 'd'))
(('e', 'f'), ('b', 'a'), ('d', 'c'))
(('f', 'e'), ('a', 'b'), ('c', 'd'))
(('f', 'e'), ('a', 'b'), ('d', 'c'))
(('f', 'e'), ('b', 'a'), ('c', 'd'))
(('f', 'e'), ('b', 'a'), ('d', 'c'))
(('e', 'f'), ('c', 'd'), ('a', 'b'))
(('e', 'f'), ('c', 'd'), ('b', 'a'))
(('e', 'f'), ('d', 'c'), ('a', 'b'))
(('e', 'f'), ('d', 'c'), ('b', 'a'))
(('f', 'e'), ('c', 'd'), ('a', 'b'))
(('f', 'e'), ('c', 'd'), ('b', 'a'))
(('f', 'e'), ('d', 'c'), ('a', 'b'))
(('f', 'e'), ('d', 'c'), ('b', 'a'))
Or to "anchor" the first element:
def permute3(s):
return s[:1] + list(p) for p in permute2(s[1:])
>>> for i in permute3(s):
... print i
[('a', 'b'), ('c', 'd'), ('e', 'f')]
[('a', 'b'), ('c', 'd'), ('f', 'e')]
[('a', 'b'), ('d', 'c'), ('e', 'f')]
[('a', 'b'), ('d', 'c'), ('f', 'e')]
[('a', 'b'), ('e', 'f'), ('c', 'd')]
[('a', 'b'), ('e', 'f'), ('d', 'c')]
[('a', 'b'), ('f', 'e'), ('c', 'd')]
[('a', 'b'), ('f', 'e'), ('d', 'c')]

Categories

Resources