【问题标题】:Permutations between two lists of unequal length两个长度不等的列表之间的排列
【发布时间】:2012-10-07 18:18:17
【问题描述】:

我无法理解我正在尝试实现的算法。我有两个列表,想从这两个列表中获取特定的组合。

这是一个例子。

names = ['a', 'b']
numbers = [1, 2]

这种情况下的输出是:

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

我的名字可能比数字多,即len(names) >= len(numbers)。这是一个包含 3 个名称和 2 个数字的示例:

names = ['a', 'b', 'c']
numbers = [1, 2]

输出:

[('a', 1), ('b', 2)]
[('b', 1), ('a', 2)]
[('a', 1), ('c', 2)]
[('c', 1), ('a', 2)]
[('b', 1), ('c', 2)]
[('c', 1), ('b', 2)]

【问题讨论】:

  • @dm03514 我看到了,并使用 itertools 找到了一些类似目标的示例,但我在 python 中进行原型设计,但会用另一种语言编写最终代码,所以我不想使用任何工具没有其他方法。
  • 您所要求的实际上没有意义。如果第一个列表包含 A、B、C,而第二个列表包含 1,2,您希望得到什么结果?如果您给出的示例有 4 个不同的结果,每个结果是一个字母和一个数字(A1、A2、B1、B2),或者两个列表必须具有相同的大小,则可以这样做。
  • 我同意 interjay。请在大小不等的情况下说明结果,否则无法提供通用解决方案。
  • 请注意,以后的人会重复这个问题:Get the cartesian product of a series of lists? 很有可能是一个更好的复制目标(很多应该使用 product 的东西在这里被复制了,甚至虽然这个问题没有以这种方式得到妥善解决)。在极少数情况下,All possible replacements of two lists? 可能会更好(当从每个索引的两个列表之一中选择一个值时,这又是一个 product 解决方案,带有 zip 预传递)。

标签: python list algorithm itertools combinatorics


【解决方案1】:

最简单的方法是使用itertools.product

a = ["foo", "melon"]
b = [True, False]
c = list(itertools.product(a, b))
>> [("foo", True), ("foo", False), ("melon", True), ("melon", False)]

【讨论】:

  • OP 没有要求笛卡尔积,并且这个答案(以及大多数其他答案)没有给出问题中指定的预期结果。
  • @interjay 你说的很对,但似乎有太多人认为这个答案是正确的,所以我只能假设问题的标题缺乏上下文。
  • @xpy 标题太短,无法解释一切。这就是为什么您需要阅读实际问题。
  • OP 想要排列组合,但 Google 会将任何寻找组合的人(比如我)发送到这个答案 - 很高兴看到它的选票是 8 倍!
【解决方案2】:

可能比上面最简单的更简单:

>>> a = ["foo", "bar"]
>>> b = [1, 2, 3]
>>> [(x,y) for x in a for y in b]  # for a list
[('foo', 1), ('foo', 2), ('foo', 3), ('bar', 1), ('bar', 2), ('bar', 3)]
>>> ((x,y) for x in a for y in b)  # for a generator if you worry about memory or time complexity.
<generator object <genexpr> at 0x1048de850>

没有任何导入

【讨论】:

  • 最佳解决方案!谢谢!其他解决方案要么完全错误,要么仅在 a > b 等特定情况下有效。
  • 最 Pythonic 的解决方案! (并避免不必要的导入)
  • 时间复杂度为 O(n^2)
  • 投注解决方案!!简单的基础永远是最好的方法
【解决方案3】:

注意:这个答案是针对上面提出的具体问题。如果您来自 Google,并且只是在寻找一种在 Python 中获取笛卡尔积的方法,itertools.product 或简单的列表理解可能是您正在寻找的 - 请参阅其他答案。


假设len(list1) &gt;= len(list2)。那么您似乎想要的是从list1 中获取长度为len(list2) 的所有排列,并将它们与list2 中的项目匹配。在python中:

import itertools
list1=['a','b','c']
list2=[1,2]

[list(zip(x,list2)) for x in itertools.permutations(list1,len(list2))]

返回

[[('a', 1), ('b', 2)], [('a', 1), ('c', 2)], [('b', 1), ('a', 2)], [('b', 1), ('c', 2)], [('c', 1), ('a', 2)], [('c', 1), ('b', 2)]]

【讨论】:

  • 结果正是我想要的,但是可以分享一下背后的逻辑吗?如果我将代码转换为 C 或 Java,我将无法使用 zip 或 itertools(尽管它们让生活变得非常轻松)
  • @user1735075 看看documentation
  • @user1735075:你知道python是开源的吗?因此,您可以简单地下载源代码并查看它们的作用。向 Steak 先生 +1 指出文档实际上有一个不使用 zip 和类似的示例实现。
  • 我真的无法让它工作,即使你的例子......我得到的只是一个 zip 对象的列表..:|
  • @logic 提供了应该被接受的解决方案。
【解决方案4】:

我正在寻找一个只有唯一组合的列表与自身相乘,它是作为这个函数提供的。

import itertools
itertools.combinations(list, n_times)

这里是the Python docs on itertools 的摘录,这可能会帮助您找到所需的内容。

Combinatoric generators:

Iterator                                 | Results
-----------------------------------------+----------------------------------------
product(p, q, ... [repeat=1])            | cartesian product, equivalent to a 
                                         |   nested for-loop
-----------------------------------------+----------------------------------------
permutations(p[, r])                     | r-length tuples, all possible 
                                         |   orderings, no repeated elements
-----------------------------------------+----------------------------------------
combinations(p, r)                       | r-length tuples, in sorted order, no 
                                         |   repeated elements
-----------------------------------------+----------------------------------------
combinations_with_replacement(p, r)      | r-length tuples, in sorted order, 
                                         | with repeated elements
-----------------------------------------+----------------------------------------
product('ABCD', repeat=2)                | AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD
permutations('ABCD', 2)                  | AB AC AD BA BC BD CA CB CD DA DB DC
combinations('ABCD', 2)                  | AB AC AD BC BD CD
combinations_with_replacement('ABCD', 2) | AA AB AC AD BB BC BD CC CD DD

【讨论】:

    【解决方案5】:

    找出大量列表的所有组合的最佳方法是:

    import itertools
    from pprint import pprint
    
    inputdata = [
        ['a', 'b', 'c'],
        ['d'],
        ['e', 'f'],
    ]
    result = list(itertools.product(*inputdata))
    pprint(result)
    

    结果将是:

    [('a', 'd', 'e'),
     ('a', 'd', 'f'),
     ('b', 'd', 'e'),
     ('b', 'd', 'f'),
     ('c', 'd', 'e'),
     ('c', 'd', 'f')]
    

    【讨论】:

    • 谢谢,很好的回答!
    【解决方案6】:

    您可能想尝试单行列表理解:

    >>> [name+number for name in 'ab' for number in '12']
    ['a1', 'a2', 'b1', 'b2']
    >>> [name+number for name in 'abc' for number in '12']
    ['a1', 'a2', 'b1', 'b2', 'c1', 'c2']
    

    【讨论】:

      【解决方案7】:

      或短名单的 KISS 答案:

      [(i, j) for i in list1 for j in list2]
      

      性能不如 itertools,但您使用的是 python,因此性能已经不是您最关心的问题...

      我也喜欢所有其他答案!

      【讨论】:

        【解决方案8】:

        对 interjay 的回答进行了微小的改进,以使结果成为扁平列表。

        >>> list3 = [zip(x,list2) for x in itertools.permutations(list1,len(list2))]
        >>> import itertools
        >>> chain = itertools.chain(*list3)
        >>> list4 = list(chain)
        [('a', 1), ('b', 2), ('a', 1), ('c', 2), ('b', 1), ('a', 2), ('b', 1), ('c', 2), ('c', 1), ('a', 2), ('c', 1), ('b', 2)]
        

        来自link的参考

        【讨论】:

          【解决方案9】:

          没有itertools 作为扁平列表:

          [(list1[i], list2[j]) for i in range(len(list1)) for j in range(len(list2))]
          

          或在 Python 2 中:

          [(list1[i], list2[j]) for i in xrange(len(list1)) for j in xrange(len(list2))]
          

          【讨论】:

            【解决方案10】:

            更好的答案只适用于提供的特定长度的列表。

            这是一个适用于任何长度输入的版本。它还使算法在组合和排列的数学概念方面变得清晰。

            from itertools import combinations, permutations
            list1 = ['1', '2']
            list2 = ['A', 'B', 'C']
            
            num_elements = min(len(list1), len(list2))
            list1_combs = list(combinations(list1, num_elements))
            list2_perms = list(permutations(list2, num_elements))
            result = [
              tuple(zip(perm, comb))
              for comb in list1_combs
              for perm in list2_perms
            ]
            
            for idx, ((l11, l12), (l21, l22)) in enumerate(result):
              print(f'{idx}: {l11}{l12} {l21}{l22}')
            

            这个输出:

            0: A1 B2
            1: A1 C2
            2: B1 A2
            3: B1 C2
            4: C1 A2
            5: C1 B2
            

            【讨论】:

              【解决方案11】:

              回答问题“给定两个列表,从每个列表中找到一个项目对的所有可能排列”并使用基本的 Python 功能(即,没有 itertools),因此,可以轻松地复制到其他编程语言:

              def rec(a, b, ll, size):
                  ret = []
                  for i,e in enumerate(a):
                      for j,f in enumerate(b):
                          l = [e+f]
                          new_l = rec(a[i+1:], b[:j]+b[j+1:], ll, size)
                          if not new_l:
                              ret.append(l)
                          for k in new_l:
                              l_k = l + k
                              ret.append(l_k)
                              if len(l_k) == size:
                                  ll.append(l_k)
                  return ret
              
              a = ['a','b','c']
              b = ['1','2']
              ll = []
              rec(a,b,ll, min(len(a),len(b)))
              print(ll)
              

              返回

              [['a1', 'b2'], ['a1', 'c2'], ['a2', 'b1'], ['a2', 'c1'], ['b1', 'c2'], ['b2', 'c1']]
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2022-11-24
                • 1970-01-01
                • 1970-01-01
                • 2013-07-18
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多