【问题标题】:Merging 2 Lists In Multiple Ways - Python以多种方式合并 2 个列表 - Python
【发布时间】:2023-03-26 02:50:01
【问题描述】:

我一直在尝试多种技术,但我确信有一些流畅的方法可以完成这项工作。

假设我有两个列表,其中包含相同数量的项目(每个 4 个):

a = ['a', 'b', 'c', 'd']    
b = [1, 2, 3, 4]

我想以所有可能的方式合并这些列表,同时保持顺序。示例输出:

a, b, c, d, 1, 2, 3, 4    
1, 2, 3, 4, a, b, c, d    
a, b, 1, 2, c, 3, 4, d

关键是每个列表都必须保持其顺序,因此考虑到它在列表中的位置,一个项目不能在输出中的另一个项目之前。所以例如输出不能是:

a, b, **d**, c, 1...   > d precedes c whereas c is before d in the original list
1, **4**, a, b, 3....  > 4 precedes 3 whereas 3 is before 4 in the original list

我想这个想法是以所有可能的方式将第二个列表合并到第一个列表中。一个完整的例子是这样的:

a = [a, b]    
b = [1, 2]

想要的输出:

ab12                                                                      
a1b2                                                                             
a12b                                                                         
1ab2                                                                             
1a2b                                                                          
12ab

我该怎么做呢? itertools 是否有能力以某种方式做到这一点?还是有其他方法可以完成这项工作?请帮忙!

【问题讨论】:

    标签: python list combinations permutation


    【解决方案1】:

    在 2x4 的情况下,您希望在不破坏每个四边形中的顺序的情况下获取所有 8 个元素。这些例子:

    a, b, c, d, 1, 2, 3, 4    
    1, 2, 3, 4, a, b, c, d    
    a, b, 1, 2, c, 3, 4, d
    

    可以转换为“指令”序列,这些指令是要从中获取的列表,0 或 1:

    0 0 0 0 1 1 1 1
    1 1 1 1 0 0 0 0
    0 0 1 1 0 1 1 0
    

    一旦您意识到这一点,您可能会注意到我们需要生成的序列都是四个零和四个一的排列。实现了这一飞跃,我们可以使用itertools

    itertools.permutations([0,0,0,0,1,1,1,1])
    

    对于 2x4 的情况,这给出了 40320 个结果,但只有 70 个唯一的结果(因为 itertools.permutations 认为 1,1,1 与 1,1,1 不同,如果数字重新排序)。您可以从此处的答案中获得独特的排列:https://stackoverflow.com/a/6285330/4323 或仅使用 set()


    综上所述,这是一个完整的解决方案:

    import itertools
    
    def combos(*seqs):
        counts = map(len, seqs)
        base = []
        for ii, count in enumerate(counts):
            base.extend([ii]*count)
        for take in set(itertools.permutations(base)):
            result = []
            where = [0] * len(seqs)
            for elem in take:
                result.append(seqs[elem][where[elem]])
                where[elem] += 1
            yield result
    

    你可以这样测试(给出 70 个结果):

    a = ['a', 'b', 'c', 'd']
    b = [1, 2, 3, 4]
    
    for res in combos(a, b):
        print res
    

    【讨论】:

    • 不错的见解,您打算制定一个实施方案吗?
    • 我添加了一个,我喜欢这种方法比递归的更好,因为它很容易概括。
    • @SiHa:谢谢,我只是在我的答案中编辑了一个关于这个问题的注释,以及如何解决它。
    • 谢谢!这很好用。逻辑很优雅。你,约翰.. 是男人!
    【解决方案2】:

    使用 python 的递归方法:

    def f( s , l1 , l2 ):
            if( l1 == [] and l2 == [] ):
                    print s
                    return
            if( l1 != [] ):
                    f( s + l1[0] , l1[1:] , l2 )
            if( l2 != [] ):
                    f( s + str(l2[0]) , l1 , l2[1:] )
    

    【讨论】:

      【解决方案3】:

      一种选择是使用计数器,其中设置位对应于a 上的项目,而取消设置为b 上的项目。对于计数器中的每个值,检查是否设置了 len(a) 位并生成排列:

      def ordered_permutations(l1, l2):
          length = len(l1) + len(l2)
          fmt = '{{0:0{0}b}}'.format(length)
      
          for i in xrange(2 ** length):
              seq = fmt.format(i)
      
              if seq.count('1') == len(l1):
                  iters = [iter(l1), iter(l2)]
                  yield [iters[int(c)].next() for c in seq]
      

      用法:

      for p in ordered_permutations(['a','b'], [1,2]):
          print p
      

      输出:

      ['a', 'b', 1, 2]
      ['a', 1, 'b', 2]
      ['a', 1, 2, 'b']
      [1, 'a', 'b', 2]
      [1, 'a', 2, 'b']
      [1, 2, 'a', 'b']
      

      可以通过使用HAKMEM 175 生成下一个序列而不是使用计数器并检查是否设置了正确数量的位来改进实现。

      【讨论】:

        【解决方案4】:

        另一种选择是使用递归。

        伪代码:

        result[] SortedMergePermutations(listA,listB)
        {
          result.append([FirstElementOfListA, 
            SortedMergePermutations(listAWithoutFirstElement,listB))]
          result.append([FirstElementOfListB,
            SortedMergePermutations(listA,listBWithoutFirstElement))]
          ])
          return result
        }
        

        【讨论】:

          【解决方案5】:

          我找到了一个只适用于两个序列的解决方案,但使用itertools.combinations() 来查找可能的位置序列,以便(按顺序...)放置第一个序列的元素

          from __future__ import print_function
          
          def print_merged(a, b):
              from itertools import combinations, cycle
          
              l = len(a) + len(b)
              ab = [cycle(a), cycle(b)]
              rng = range(l)
              print([a, b])
          
              for index in combinations(rng, len(a)):
                  li = []
                  for i in rng:
                      n = 0 if i in index else 1
                      li.append(next(ab[n]))
                  print(li)
          
          # testing
          
          print_merged([1,2,3], [4,5,6])
          print('-'*72)
          print_merged([1,2], [4,5,6])
          print('-'*72)
          print_merged([1,2,3], [5,6])
          

          我隐约明白,可以处理大量列表,将第三个列表与第一个和第二个生成的每个列表合并,等等,这个想法指向递归实现的方向,但我很高兴把这样的成就留给别人...

          编辑 1

          我已经移除了计数器机制,因为 itertools.cycle() 对象正是我们所需要的。

          测试输出

          [[1, 2, 3], [4, 5, 6]]
          [1, 2, 3, 4, 5, 6]
          [1, 2, 4, 3, 5, 6]
          [1, 2, 4, 5, 3, 6]
          [1, 2, 4, 5, 6, 3]
          [1, 4, 2, 3, 5, 6]
          [1, 4, 2, 5, 3, 6]
          [1, 4, 2, 5, 6, 3]
          [1, 4, 5, 2, 3, 6]
          [1, 4, 5, 2, 6, 3]
          [1, 4, 5, 6, 2, 3]
          [4, 1, 2, 3, 5, 6]
          [4, 1, 2, 5, 3, 6]
          [4, 1, 2, 5, 6, 3]
          [4, 1, 5, 2, 3, 6]
          [4, 1, 5, 2, 6, 3]
          [4, 1, 5, 6, 2, 3]
          [4, 5, 1, 2, 3, 6]
          [4, 5, 1, 2, 6, 3]
          [4, 5, 1, 6, 2, 3]
          [4, 5, 6, 1, 2, 3]
          ------------------------------------------------------------------------
          [[1, 2], [4, 5, 6]]
          [1, 2, 4, 5, 6]
          [1, 4, 2, 5, 6]
          [1, 4, 5, 2, 6]
          [1, 4, 5, 6, 2]
          [4, 1, 2, 5, 6]
          [4, 1, 5, 2, 6]
          [4, 1, 5, 6, 2]
          [4, 5, 1, 2, 6]
          [4, 5, 1, 6, 2]
          [4, 5, 6, 1, 2]
          ------------------------------------------------------------------------
          [[1, 2, 3], [5, 6]]
          [1, 2, 3, 5, 6]
          [1, 2, 5, 3, 6]
          [1, 2, 5, 6, 3]
          [1, 5, 2, 3, 6]
          [1, 5, 2, 6, 3]
          [1, 5, 6, 2, 3]
          [5, 1, 2, 3, 6]
          [5, 1, 2, 6, 3]
          [5, 1, 6, 2, 3]
          [5, 6, 1, 2, 3]
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2022-11-29
            • 2022-06-28
            • 2023-01-18
            • 2010-11-23
            • 2021-03-24
            • 2015-09-21
            • 1970-01-01
            • 2016-03-01
            相关资源
            最近更新 更多