Как составить вложенную и сгруппированную комбинацию элементов списка? - PullRequest
0 голосов
/ 19 апреля 2020

Надеюсь, заголовок вопроса понятен, если не здесь, подробности.

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


Вывод:

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


Я на самом деле пытаюсь составьте комбинацию таким образом, чтобы две дополнительные комбинации также были сгруппированы вместе. то есть, если 'A' было выбрано из lis_a с 'T' из lis_b, то 'C' из lis_a с 'G' из lis_b было бы дополнительным.

Я на самом деле хочу все возможные состояния в следующем формате, где два дополнительных состояния вложены вместе:

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

Ответы [ 3 ]

2 голосов
/ 19 апреля 2020

Вы можете сделать это, канонизируя каждую последовательность к минимуму самой себя и ее дополнения. Взяв минимум, вы гарантируете, что последовательность и ее дополнение отображаются в одно и то же канонизированное представление.

Затем вы можете сгруппировать их и найти пары. A defaultdict облегчает группировку.

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')]]
2 голосов
/ 19 апреля 2020

Вы можете использовать тот факт, что ваши списки являются просто 2-кортежами (технически списки длины 2) и использовать двоичный XOR ^ для 1, чтобы получить дополнительный элемент

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

Вывод:

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

Если вы хотите получить набор без повторяющихся перестановок (например, первая и последняя строка в выводе выше), вы можете использовать следующее:

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

Выход:

('A', 'T', 'G') ('C', 'G', 'T')
('A', 'T', 'T') ('C', 'G', 'G')
('A', 'G', 'G') ('C', 'T', 'T')
('A', 'G', 'T') ('C', 'T', 'G')
0 голосов
/ 19 апреля 2020

Посмотрите на itertools.combination:

itertools.combinations(iterable, r)

Возвращает подпоследовательности r элементов длины из итеративного ввода.

Комбинации генерируются в лексикографическом порядке c сортировки. Таким образом, если входной повторяемый элемент отсортирован, комбинированные кортежи будут созданы в отсортированном порядке.

...