【问题标题】:create all possible combinations with multiple variants from list从列表中创建具有多个变体的所有可能组合
【发布时间】:2020-05-31 13:41:27
【问题描述】:

好的,问题如下:

假设我有一个像[12R,102A,102L,250L] 这样的列表,我想要的是所有可能组合的列表,但是只有一个组合/数字。所以对于上面的例子,我想要的输出是:

[12R,102A,250L]
[12R,102L,250L]

我的实际问题要复杂得多,站点更多。感谢您的帮助

编辑:在阅读了一些 cmets 之后,我想这有点不清楚。我在这里有 3 个唯一数字,[12、102 和 250],对于某些数字,我有不同的变体,例如 [102A、102L]。我需要的是一种方法来组合不同的位置[12,102,250] 和所有可能的变化。就像我在上面介绍的列表一样。它们是唯一有效的解决方案。 [12R] 不是。 [12R,102A,102L,250L] 也不是。到目前为止,我已经使用嵌套循环完成了这项工作,但是这些数字中有很多变化,所以我真的不能再这样做了

我会再次编辑这个:好的,所以似乎仍然存在一些混乱,所以我可能会扩展我之前提出的观点。我正在处理的是DNA。 12R表示序列中的第12位变成了R。所以溶液[12R,102A,250L]表示第12位的氨基酸是R,102是A,250是L。

这就是为什么像 [102L, 102R, 250L] 这样的解决方案不可用的原因,因为相同的位置不能被 2 个不同的氨基酸占据。

谢谢

【问题讨论】:

  • 是否有可能拥有例如[102A,12R,102L,250L],或者它是给定的,相同的数字总是彼此相邻?
  • Wouid [12R] [12R,102A] 也是有效输出吗?
  • 不,有效的输出是每个点的组合,就像我提供的列表一样。
  • 值是否按可预测的顺序排序?

标签: python


【解决方案1】:

您可以使用递归生成器函数:

from itertools import groupby as gb
import re

def combos(d, c = []):
  if not d:
     yield c
  else:
     for a, b in d[0]:
       yield from combos(d[1:], c + [a+b]) 

d = ['12R', '102A', '102L', '250L']
vals = [re.findall('^\d+|\w+$', i) for i in d]
new_d = [list(b) for _, b in gb(sorted(vals, key=lambda x:x[0]), key=lambda x:x[0])]
print(list(combos(new_d)))

输出:

[['102A', '12R', '250L'], ['102L', '12R', '250L']]

【讨论】:

    【解决方案2】:

    所以它适用于["10A","100B","12C","100R"](案例1)和['12R','102A','102L','250L'](案例2)

    import itertools as it
    
    liste = ['12R','102A','102L','250L']
    
    comb = []
    for e in it.combinations(range(4), 3):
        e1 = liste[e[0]][:-1]
        e2 = liste[e[1]][:-1]
        e3 = liste[e[2]][:-1]
        if e1 != e2 and e2 != e3 and e3 != e1:
            comb.append([e1+liste[e[0]][-1], e2+liste[e[1]][-1], e3+liste[e[2]][-1]])
    print(list(comb))
    # case 1 : [['10A', '100B', '12C'], ['10A', '12C', '100R']]
    # case 2 : [['12R', '102A', '250L'], ['12R', '102L', '250L']]
    
    

    【讨论】:

    • 你们可以在评论之前阅读问题。这不是我需要的,我提供的示例输出不清楚吗?
    • 我认为“但是只有一个组合/数字”不清楚。
    • 我想所以我相信你想要所有可能的组合
    • 我给出的输出是我想要的输出。所以在每个唯一的数字我得到所有可能的组合。我想我解决这个问题的一种方法是使用嵌套循环,但我有数百种不同的变体,所以这不起作用
    • ['102A', '102L', '250L'],还是不行。它不能多次出现在同一个位置(102)。唯一有效的解决方案是我在原始问题中发布的 2 个列表。 ['12R', '102A', '102L'] 也是错误的
    【解决方案3】:
    import re
    
    def get_grouped_options(input):
         options = {}
         for option in input:
              m = re.match('([\d]+)([A-Z])$', option)
              if m:
                   position = int(m.group(1))
                   acid = m.group(2)
              else:
                   continue
              if position not in options:
                   options[position] = []
              options[position].append(acid)
         return options
    
    
    def yield_all_combos(options):
         n = len(options)
         positions = list(options.keys())
         indices = [0] * n
         while True:
              yield ["{}{}".format(position, options[position][indices[i]])
                     for i, position in enumerate(positions)]
              j = 0
              indices[j] += 1
              while indices[j] == len(options[positions[j]]):
                   # carry
                   indices[j] = 0
                   j += 1
                   if j == n:
                        # overflow
                        return
                   indices[j] += 1
    
    
    input = ['12R', '102A', '102L', '250L']
    
    options = get_grouped_options(input)
    
    for combo in yield_all_combos(options):
         print("[{}]".format(",".join(combo)))
    

    给予:

    [12R,102A,250L]
    [12R,102L,250L]
    

    【讨论】:

      【解决方案4】:

      试试这个:

      from itertools import groupby
      import re
      
      def __genComb(arr, res=[]):
          for i in range(len(res), len(arr)):
              el=arr[i]
              if(len(el[1])==1):
                  res+=el[1]
              else:
                  for el_2 in el[1]:
                      yield from __genComb(arr, res+[el_2])
                  break
          if(len(res)==len(arr)): yield res
      
      def genComb(arr):
          res=[(k, list(v)) for k,v in groupby(sorted(arr), key=lambda x: re.match(r"(\d*)", x).group(1))]
          yield from __genComb(res)
      

      示例输出(使用您提供的输入):

      test=["12R","102A","102L","250L"]
      
      for el in genComb(test):
          print(el)
      
      # returns:
      
      ['102A', '12R', '250L']
      ['102L', '12R', '250L']
      

      【讨论】:

      • 你好,大部分都是无效的,抱歉。唯一可接受的解决方案是我在上面发布的 2 个列表。我试图编辑 OP 以使问题更清楚
      • 立即查看 - 我在您的输入中添加了一个元素
      • (当我们接受您提供的输入时,它会模仿您想要的输出)
      • 好的,调整了我的答案——所以你的输入和你的问题一样;)
      • 嘿,当我使用不同的列表时,例如 test = ["10A","100B","12C","100R"] 我返回 ['12R', '100B', '12C','100R']。当我用我的实际列表尝试它时它也不起作用,这个列表要大得多
      【解决方案5】:

      我相信这就是你要找的东西!

      这是由

      • 生成每个前缀可以具有的所有后缀的集合
      • 查找位置总数(将每个子列表的长度相乘)
      • 通过基于集合中成员后缀位置和绝对结果索引(最终结果中的已知位置)的读取索引来循环遍历每个后缀
      import collections
      import functools
      import operator
      import re
      
      # initial input
      starting_values = ["12R","102A","102L","250L"]
      
      d = collections.defaultdict(list)  # use a set if duplicates are possible
      for value in starting_values:
          numeric, postfix = re.match(r"(\d+)(.*)", value).groups()
          d[numeric].append(postfix)  # .* matches ""; consider (postfix or "_") to give value a size
      
      # d is now a dictionary of lists where each key is the prefix
      # and each value is a list of possible postfixes
      
      
      # each set of postfixes multiplies the total combinations by its length
      total_combinations = functools.reduce(
          operator.mul,
          (len(sublist) for sublist in d.values())
      )
      
      results = collections.defaultdict(list)
      for results_pos in range(total_combinations):
          for index, (prefix, postfix_set) in enumerate(d.items()):
              results[results_pos].append(
                  "{}{}".format(  # recombine the values
                      prefix,     # numeric prefix
                      postfix_set[(results_pos + index) % len(postfix_set)]
                  ))
      
      # results is now a dictionary mapping { result index: unique list }
      

      显示

      # set width of column by longest prefix string
      # need a collection for intermediate cols, but beyond scope of Q
      col_width = max(len(str(k)) for k in results)
      for k, v in results.items():
          print("{:<{w}}: {}".format(k, v, w=col_width))
      
      
      0: ['12R', '102L', '250L']
      1: ['12R', '102A', '250L']
      

      具有更高级的输入

      ["12R","102A","102L","250L","1234","1234A","1234C"]
      
      0: ['12R', '102L', '250L', '1234']
      1: ['12R', '102A', '250L', '1234A']
      2: ['12R', '102L', '250L', '1234C']
      3: ['12R', '102A', '250L', '1234']
      4: ['12R', '102L', '250L', '1234A']
      5: ['12R', '102A', '250L', '1234C']
      

      您可以使用set 确认这些值确实是唯一的

      final = set(",".join(x) for x in results.values())
      for f in final:
          print(f)
      
      12R,102L,250L,1234
      12R,102A,250L,1234A
      12R,102L,250L,1234C
      12R,102A,250L,1234
      12R,102L,250L,1234A
      12R,102A,250L,1234C
      

      注释

      【讨论】:

        猜你喜欢
        • 2018-06-08
        • 2014-09-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多