【问题标题】:How to make a nested and grouped combination of the elements of the list?如何对列表的元素进行嵌套和分组组合?
【发布时间】:2020-04-19 19:52:18
【问题描述】:

我希望问题的标题很清楚,如果没有,这里有更多细节。

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


我实际上是在尝试以一种使两个互补组合也组合在一起的方式进行组合。 即,如果从 lis_a 中选择了“A”,而从 lis_b 中选择了“T”,那么 lis_a 中的“C”和 lis_b 中的“G”将是互补的。

我实际上希望所有可能的状态都采用以下格式,其中两个互补状态嵌套在一起:

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

【问题讨论】:

  • 在我看来,你想要的只是list(itertools.product(lis_a, lis_b, lis_c)),除非我错过了什么
  • 您是在寻找示例输出中显示的所有可能组合,还是您所说的互补组合?
  • @DeepSpace:互补序列(或状态)需要嵌套在一起。这是我面临的主要问题。
  • @GrandPhuba:我想要所有可能的组合(这已经是列表理解),但在所有可能的组合中,我还希望互补状态嵌套在一起。

标签: python list list-comprehension combinations permutation


【解决方案1】:

您可以利用您的列表只是 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')

【讨论】:

  • 仅供参考,Python 中的“二进制不”实际上会给出-(i+1),因为数字没有固定的位宽。您的代码有效,但我认为不是您所期望的。试试这些:~0 # -1~1 # -2。您可能更喜欢 1-i 等介于 01 之间。或者i^1,你可以选择:)
  • @mcskinner 谢谢你。更新为使用 XOR x^1 然后
  • 没问题。我提交了要匹配的列表理解的编辑。如果所有输入列表都保证是补码对,这是一种很好的处理方式。
  • 已经编辑过但感谢@mcskinner。还有一点一文不值,这个解决方案会产生与 OP 所需输出相反的重复项,但我同时保留了答案,因为它只是建立在 OP 提供的输入之上。
  • @everestial007 将我的答案更新为只有唯一的组合。至于~a和^,它们被称为按位运算符,这意味着它对数字的二进制数字进行运算。欲了解更多信息,请查看python-reference.readthedocs.io/en/latest/docs/operators/…
【解决方案2】:

您可以通过将每个序列规范化为自身及其补码的最小值来做到这一点。通过取最小值,您可以保证序列及其补码都映射到相同的规范化表示。

然后您可以按此分组并找到对。 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')]]

【讨论】:

    【解决方案3】:

    看看 itertools.combinations:

    itertools.combinations(iterable, r)
    

    从输入迭代中返回 r 个长度的元素子序列。

    组合按字典排序顺序发出。因此,如果输入的可迭代对象已排序,则组合元组将按排序顺序生成。

    【讨论】:

    • 什么是r?请提供更多详细信息。
    • iterable is will be 'ACTG' and r will be 3 简单示例:print(list(combinations('12345',2))) [('1', '2'), (' 1', '3'), ('1', '4'), ('1', '5'), ('2', '3'), ('2', '4'), (' 2', '5'), ('3', '4'), ('3', '5'), ('4', '5')]
    猜你喜欢
    • 2021-04-29
    • 1970-01-01
    • 2021-07-14
    • 2017-05-30
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    • 1970-01-01
    • 2016-12-13
    相关资源
    最近更新 更多