Reputation: 7255
I hope the title of the question is clear, if not here is more details.
lis_a, lis_b, lis_c = ['A', 'C'], ['T', 'G'], ['G', 'T']
# I am trying make combination of these list elements
all_possible_states = [[x, y, z] for x in lis_a for y in lis_b for z in lis_c]
print('all possible states')
Output is:
all possible states
[['A', 'T', 'G'], ['A', 'T', 'T'], ['A', 'G', 'G'], ['A', 'G', 'T'], ['C', 'T', 'G'], ['C', 'T', 'T'], ['C', 'G', 'G'], ['C', 'G', 'T']]
I am actually trying to make a combination in a way such that the two complementary combination are also grouped together. i.e if 'A' was selected from lis_a with 'T' from lis_b then 'C' from lis_a with 'G' from lis_b would be it's complementary.
I actually want all possible state in following format where two complementary states are nested together:
[[['A', 'T', 'G'], ['C', 'G', 'T']], [['A', 'T', 'T'], ['C', 'G', 'G']], [['A', 'G', 'G'], [['A', 'G', 'T'], ['C', 'T', 'G']]]
Or,
[(['A', 'T', 'G'], ['C', 'G', 'T']), (['A', 'T', 'T'], ['C', 'G', 'G']), (['A', 'G', 'G'], ['C', 'T', 'T']), (['A', 'G', 'T'], ['C', 'T', 'G'])]
Upvotes: 0
Views: 95
Reputation: 2919
You can leverage the fact that your lists are just 2-tuples (technically lists of lengths 2) and use binary XOR ^
to 1 to get the complementary element
lis_a, lis_b, lis_c = ['A', 'C'], ['T', 'G'], ['G', 'T']
states = []
for i, x in enumerate(lis_a):
for j, y in enumerate(lis_b):
for k, z in enumerate(lis_c):
state = (x, y, z)
complement = (lis_a[i^1], lis_b[j^1], lis_c[k^1])
print(state, complement)
states.append((state, complement))
# As a comprehension:
# states = [((x, y, z), (lis_a[i^1], lis_b[j^1], lis_c[k^1])) for i, x in enumerate(lis_a) for j, y in enumerate(lis_b) for k, z in enumerate(lis_c)]
Output:
('A', 'T', 'G') ('C', 'G', 'T')
('A', 'T', 'T') ('C', 'G', 'G')
('A', 'G', 'G') ('C', 'T', 'T')
('A', 'G', 'T') ('C', 'T', 'G')
('C', 'T', 'G') ('A', 'G', 'T')
('C', 'T', 'T') ('A', 'G', 'G')
('C', 'G', 'G') ('A', 'T', 'T')
('C', 'G', 'T') ('A', 'T', 'G')
If you want to get a set with no repeated permutations (e.g. the first and last line in the output above), you can use the following:
lis_a, lis_b, lis_c = ['A', 'C'], ['T', 'G'], ['G', 'T']
states = []
for num in range(4):
k, j, i = num & 1, (num >> 1) & 1, (num >> 2) & 1 # 000, 001, 010, 011
state = lis_a[i], lis_b[j], lis_c[k]
compliment = lis_a[i ^ 1], lis_b[j ^ 1], lis_c[k ^ 1]
print(state, compliment)
states.append((state, compliment))
Output:
('A', 'T', 'G') ('C', 'G', 'T')
('A', 'T', 'T') ('C', 'G', 'G')
('A', 'G', 'G') ('C', 'T', 'T')
('A', 'G', 'T') ('C', 'T', 'G')
Upvotes: 2
Reputation: 2748
You can do this by canonicalizing each sequence to the minimum of itself and its complement. By taking the minimum you guarantee that a sequence and its complement both map to the same canonicalized representation.
Then you can group by this and find the pairs. A defaultdict
makes the grouping easy.
import collections
import itertools
def canonicalize(seq):
complements = {'A': 'C', 'C': 'A', 'G': 'T', 'T': 'G'}
comp = tuple(complements[o] for o in seq)
return min(seq, comp)
grouped = collections.defaultdict(list)
for seq in itertools.product(lis_a, lis_b, lis_c):
grouped[canonicalize(seq)].append(seq)
list(grouped.values())
# [[('A', 'T', 'G'), ('C', 'G', 'T')],
# [('A', 'T', 'T'), ('C', 'G', 'G')],
# [('A', 'G', 'G'), ('C', 'T', 'T')],
# [('A', 'G', 'T'), ('C', 'T', 'G')]]
Upvotes: 2
Reputation: 84
Have a look at itertools.combinations:
itertools.combinations(iterable, r)
Return r length subsequences of elements from the input iterable.
Combinations are emitted in lexicographic sort order. So, if the input iterable is sorted, the combination tuples will be produced in sorted order.
Upvotes: -2