简体   繁体   English

python 中的递归排列

[英]permutations with recursion in python

I have a task to make a code that takes a list of undefined number and print all permutations with the first constant using recursion and here is a code I wrote but I don't know where is the problem我的任务是编写一个代码,该代码采用未定义数字列表并使用递归打印带有第一个常量的所有排列,这是我编写的代码,但我不知道问题出在哪里

 portnames = ["PAN", "AMS", "CAS", "NYC", "HEL"]


def permutations(route, ports):
    for items in ports:
        route.append(ports)
        ports = ports[:items]+ports[items+1:]
        permutations(route, ports)
    print(' '.join([portnames[i] for i in route]))


permutations([0], list(range(1, len(portnames))))

note: the function must contain注意:function 必须包含

We can write permutations(t) of any iterable t using inductive reasoning -我们可以使用归纳推理编写任何可迭代tpermutations(t) -

  1. if t is empty, yield the empty permutation, ()如果t为空,则产生空排列, ()
  2. (inductive) t has at least one element. (感性) t至少有一个元素。 For all p of the recursive sub-problem permutations(t[1:]) , for all i of inserts(p, t[0]) , yield i对于所有p的递归子问题permutations(t[1:]) ,对于所有iinserts(p, t[0]) ,产生i
def permutations(t):
  if not t:
    yield ()                       # 1. empty t
  else:
    for p in permutations(t[1:]):  # 2. at least one element
      for i in inserts(p, t[0]):
        yield i

Where inserts(t, x) can be written using inductive reasoning as well -其中inserts(t, x)也可以使用归纳推理来编写 -

  1. If the input t is empty, yield the final insert, (x)如果输入t为空,则产生最终插入, (x)
  2. (inductive) t has at least one element. (感性) t至少有一个元素。 yield x prepended to t and for all i of the recursive sub-problem inserts(t[1:], x) yield t[0] prepended to i yield x附加到t并且对于所有i递归子问题inserts(t[1:], x) yield t[0]附加到i
def inserts(t, x):
  if not t:
    yield (x,)                       # 1. empty t
  else:
    yield (x, *t)                    # 2. at least one element
    for i in inserts(t[1:], x):
      yield (t[0], *i)
t = ("🔴","🟢","🔵","🟡")
for p in permutations(t):
  print("".join(p))
🔴🟢🔵🟡
🟢🔴🔵🟡
🟢🔵🔴🟡
🟢🔵🟡🔴
🔴🔵🟢🟡
🔵🔴🟢🟡
🔵🟢🔴🟡
🔵🟢🟡🔴
🔴🔵🟡🟢
🔵🔴🟡🟢
🔵🟡🔴🟢
🔵🟡🟢🔴
🔴🟢🟡🔵
🟢🔴🟡🔵
🟢🟡🔴🔵
🟢🟡🔵🔴
🔴🟡🟢🔵
🟡🔴🟢🔵
🟡🟢🔴🔵
🟡🟢🔵🔴
🔴🟡🔵🟢
🟡🔴🔵🟢
🟡🔵🔴🟢
🟡🔵🟢🔴

Python has strong support for generators and offers delegation using yield from.. . Python 对生成器有强大的支持,并使用yield from..提供委托。 We can simplify the above definitions while maintaining the exact same behaviour -我们可以简化上述定义,同时保持完全相同的行为 -

def permutations(t):
  if not t:
    yield ()
  else:
    for p in permutations(t[1:]):
      yield from inserts(p, t[0])  # <-
def inserts(t, x):
  if not t:
    yield (x,)
  else:
    yield (x, *t)
    yield from map(lambda r: (t[0], *r), inserts(t[1:], x)) # <-

Generators are a good fit for combinatorics because working with them is natural and straightforward -生成器非常适合组合数学,因为使用它们是自然而直接的 -

# find all permutations where red is left of green
for p in permutations(t):
  if p.index("🔴") < p.index("🟢"):
    print("".join(p))
🔴🟢🔵🟡
🔴🔵🟢🟡
🔵🔴🟢🟡
🔴🔵🟡🟢
🔵🔴🟡🟢
🔵🟡🔴🟢
🔴🟢🟡🔵
🔴🟡🟢🔵
🟡🔴🟢🔵
🔴🟡🔵🟢
🟡🔴🔵🟢
🟡🔵🔴🟢
# find all permutations where blue and yellow are adjacent
for p in permutations(t):
  if abs(p.index("🔵") - p.index("🟡")) == 1:
    print("".join(p))
🔴🟢🔵🟡
🟢🔴🔵🟡
🟢🔵🟡🔴
🔴🔵🟡🟢
🔵🟡🔴🟢
🔵🟡🟢🔴
🔴🟢🟡🔵
🟢🔴🟡🔵
🟢🟡🔵🔴
🔴🟡🔵🟢
🟡🔵🔴🟢
🟡🔵🟢🔴

Additionally generators can be paused/stopped at any time, allowing us to skip potentially millions of computations for significantly large problems -此外,生成器可以随时暂停/停止,允许我们跳过潜在的数百万次计算以解决非常大的问题 -

# which permutation is in rainbow order?
for (n, p) in enumerate(permutations(t)):
  if p == ("🔴", "🟡", "🟢", "🔵"):
    print(f"permutation {n} is in rainbow order, {p}")
    break  # <- stops generating additional permutations
permutation 16 is in rainbow order, ('🔴', '🟡', '🟢', '🔵')

We use permutations with your portnames data now -我们现在对您的portnames数据使用permutations -

portnames = ["PAN", "AMS", "CAS", "NYC", "HEL"]
for x in permutations(portnames):
  print(x)
('PAN', 'AMS', 'CAS', 'NYC', 'HEL')
('AMS', 'PAN', 'CAS', 'NYC', 'HEL')
('AMS', 'CAS', 'PAN', 'NYC', 'HEL')
('AMS', 'CAS', 'NYC', 'PAN', 'HEL')
('AMS', 'CAS', 'NYC', 'HEL', 'PAN')
('PAN', 'CAS', 'AMS', 'NYC', 'HEL')
('CAS', 'PAN', 'AMS', 'NYC', 'HEL')
('CAS', 'AMS', 'PAN', 'NYC', 'HEL')
('CAS', 'AMS', 'NYC', 'PAN', 'HEL')
('CAS', 'AMS', 'NYC', 'HEL', 'PAN')
('PAN', 'CAS', 'NYC', 'AMS', 'HEL')
('CAS', 'PAN', 'NYC', 'AMS', 'HEL')
('CAS', 'NYC', 'PAN', 'AMS', 'HEL')
('CAS', 'NYC', 'AMS', 'PAN', 'HEL')
('CAS', 'NYC', 'AMS', 'HEL', 'PAN')
('PAN', 'CAS', 'NYC', 'HEL', 'AMS')
('CAS', 'PAN', 'NYC', 'HEL', 'AMS')
('CAS', 'NYC', 'PAN', 'HEL', 'AMS')
('CAS', 'NYC', 'HEL', 'PAN', 'AMS')
('CAS', 'NYC', 'HEL', 'AMS', 'PAN')
('PAN', 'AMS', 'NYC', 'CAS', 'HEL')
('AMS', 'PAN', 'NYC', 'CAS', 'HEL')
('AMS', 'NYC', 'PAN', 'CAS', 'HEL')
('AMS', 'NYC', 'CAS', 'PAN', 'HEL')
('AMS', 'NYC', 'CAS', 'HEL', 'PAN')
('PAN', 'NYC', 'AMS', 'CAS', 'HEL')
('NYC', 'PAN', 'AMS', 'CAS', 'HEL')
('NYC', 'AMS', 'PAN', 'CAS', 'HEL')
('NYC', 'AMS', 'CAS', 'PAN', 'HEL')
('NYC', 'AMS', 'CAS', 'HEL', 'PAN')
('PAN', 'NYC', 'CAS', 'AMS', 'HEL')
('NYC', 'PAN', 'CAS', 'AMS', 'HEL')
('NYC', 'CAS', 'PAN', 'AMS', 'HEL')
('NYC', 'CAS', 'AMS', 'PAN', 'HEL')
('NYC', 'CAS', 'AMS', 'HEL', 'PAN')
('PAN', 'NYC', 'CAS', 'HEL', 'AMS')
('NYC', 'PAN', 'CAS', 'HEL', 'AMS')
('NYC', 'CAS', 'PAN', 'HEL', 'AMS')
('NYC', 'CAS', 'HEL', 'PAN', 'AMS')
('NYC', 'CAS', 'HEL', 'AMS', 'PAN')
('PAN', 'AMS', 'NYC', 'HEL', 'CAS')
('AMS', 'PAN', 'NYC', 'HEL', 'CAS')
('AMS', 'NYC', 'PAN', 'HEL', 'CAS')
('AMS', 'NYC', 'HEL', 'PAN', 'CAS')
('AMS', 'NYC', 'HEL', 'CAS', 'PAN')
('PAN', 'NYC', 'AMS', 'HEL', 'CAS')
('NYC', 'PAN', 'AMS', 'HEL', 'CAS')
('NYC', 'AMS', 'PAN', 'HEL', 'CAS')
('NYC', 'AMS', 'HEL', 'PAN', 'CAS')
('NYC', 'AMS', 'HEL', 'CAS', 'PAN')
('PAN', 'NYC', 'HEL', 'AMS', 'CAS')
('NYC', 'PAN', 'HEL', 'AMS', 'CAS')
('NYC', 'HEL', 'PAN', 'AMS', 'CAS')
('NYC', 'HEL', 'AMS', 'PAN', 'CAS')
('NYC', 'HEL', 'AMS', 'CAS', 'PAN')
('PAN', 'NYC', 'HEL', 'CAS', 'AMS')
('NYC', 'PAN', 'HEL', 'CAS', 'AMS')
('NYC', 'HEL', 'PAN', 'CAS', 'AMS')
('NYC', 'HEL', 'CAS', 'PAN', 'AMS')
('NYC', 'HEL', 'CAS', 'AMS', 'PAN')
('PAN', 'AMS', 'CAS', 'HEL', 'NYC')
('AMS', 'PAN', 'CAS', 'HEL', 'NYC')
('AMS', 'CAS', 'PAN', 'HEL', 'NYC')
('AMS', 'CAS', 'HEL', 'PAN', 'NYC')
('AMS', 'CAS', 'HEL', 'NYC', 'PAN')
('PAN', 'CAS', 'AMS', 'HEL', 'NYC')
('CAS', 'PAN', 'AMS', 'HEL', 'NYC')
('CAS', 'AMS', 'PAN', 'HEL', 'NYC')
('CAS', 'AMS', 'HEL', 'PAN', 'NYC')
('CAS', 'AMS', 'HEL', 'NYC', 'PAN')
('PAN', 'CAS', 'HEL', 'AMS', 'NYC')
('CAS', 'PAN', 'HEL', 'AMS', 'NYC')
('CAS', 'HEL', 'PAN', 'AMS', 'NYC')
('CAS', 'HEL', 'AMS', 'PAN', 'NYC')
('CAS', 'HEL', 'AMS', 'NYC', 'PAN')
('PAN', 'CAS', 'HEL', 'NYC', 'AMS')
('CAS', 'PAN', 'HEL', 'NYC', 'AMS')
('CAS', 'HEL', 'PAN', 'NYC', 'AMS')
('CAS', 'HEL', 'NYC', 'PAN', 'AMS')
('CAS', 'HEL', 'NYC', 'AMS', 'PAN')
('PAN', 'AMS', 'HEL', 'CAS', 'NYC')
('AMS', 'PAN', 'HEL', 'CAS', 'NYC')
('AMS', 'HEL', 'PAN', 'CAS', 'NYC')
('AMS', 'HEL', 'CAS', 'PAN', 'NYC')
('AMS', 'HEL', 'CAS', 'NYC', 'PAN')
('PAN', 'HEL', 'AMS', 'CAS', 'NYC')
('HEL', 'PAN', 'AMS', 'CAS', 'NYC')
('HEL', 'AMS', 'PAN', 'CAS', 'NYC')
('HEL', 'AMS', 'CAS', 'PAN', 'NYC')
('HEL', 'AMS', 'CAS', 'NYC', 'PAN')
('PAN', 'HEL', 'CAS', 'AMS', 'NYC')
('HEL', 'PAN', 'CAS', 'AMS', 'NYC')
('HEL', 'CAS', 'PAN', 'AMS', 'NYC')
('HEL', 'CAS', 'AMS', 'PAN', 'NYC')
('HEL', 'CAS', 'AMS', 'NYC', 'PAN')
('PAN', 'HEL', 'CAS', 'NYC', 'AMS')
('HEL', 'PAN', 'CAS', 'NYC', 'AMS')
('HEL', 'CAS', 'PAN', 'NYC', 'AMS')
('HEL', 'CAS', 'NYC', 'PAN', 'AMS')
('HEL', 'CAS', 'NYC', 'AMS', 'PAN')
('PAN', 'AMS', 'HEL', 'NYC', 'CAS')
('AMS', 'PAN', 'HEL', 'NYC', 'CAS')
('AMS', 'HEL', 'PAN', 'NYC', 'CAS')
('AMS', 'HEL', 'NYC', 'PAN', 'CAS')
('AMS', 'HEL', 'NYC', 'CAS', 'PAN')
('PAN', 'HEL', 'AMS', 'NYC', 'CAS')
('HEL', 'PAN', 'AMS', 'NYC', 'CAS')
('HEL', 'AMS', 'PAN', 'NYC', 'CAS')
('HEL', 'AMS', 'NYC', 'PAN', 'CAS')
('HEL', 'AMS', 'NYC', 'CAS', 'PAN')
('PAN', 'HEL', 'NYC', 'AMS', 'CAS')
('HEL', 'PAN', 'NYC', 'AMS', 'CAS')
('HEL', 'NYC', 'PAN', 'AMS', 'CAS')
('HEL', 'NYC', 'AMS', 'PAN', 'CAS')
('HEL', 'NYC', 'AMS', 'CAS', 'PAN')
('PAN', 'HEL', 'NYC', 'CAS', 'AMS')
('HEL', 'PAN', 'NYC', 'CAS', 'AMS')
('HEL', 'NYC', 'PAN', 'CAS', 'AMS')
('HEL', 'NYC', 'CAS', 'PAN', 'AMS')
('HEL', 'NYC', 'CAS', 'AMS', 'PAN')

You can user the itertools module for this.您可以为此使用 itertools 模块。

Basically, when doing permutations and combinations, this is a very useful place.基本上,在进行排列组合时,这是一个非常有用的地方。


import itertools

portnames = ["PAN", "AMS", "CAS", "NYC", "HEL"]


x = itertools.permutations(portnames)
y = list(x)

# or this is you want to inspect the loop
# y = []
# for i in x:
#     y.append(i)

y

The result is a big list:结果是一个大列表:

[('PAN', 'AMS', 'CAS', 'NYC', 'HEL')
('PAN', 'AMS', 'CAS', 'HEL', 'NYC')
('PAN', 'AMS', 'NYC', 'CAS', 'HEL')
('PAN', 'AMS', 'NYC', 'HEL', 'CAS')
('PAN', 'AMS', 'HEL', 'CAS', 'NYC')
('PAN', 'AMS', 'HEL', 'NYC', 'CAS')
('PAN', 'CAS', 'AMS', 'NYC', 'HEL')
('PAN', 'CAS', 'AMS', 'HEL', 'NYC')
('PAN', 'CAS', 'NYC', 'AMS', 'HEL')
('PAN', 'CAS', 'NYC', 'HEL', 'AMS')
('PAN', 'CAS', 'HEL', 'AMS', 'NYC')
('PAN', 'CAS', 'HEL', 'NYC', 'AMS')
('PAN', 'NYC', 'AMS', 'CAS', 'HEL')
('PAN', 'NYC', 'AMS', 'HEL', 'CAS')
('PAN', 'NYC', 'CAS', 'AMS', 'HEL')
('PAN', 'NYC', 'CAS', 'HEL', 'AMS')
('PAN', 'NYC', 'HEL', 'AMS', 'CAS')
('PAN', 'NYC', 'HEL', 'CAS', 'AMS')
('PAN', 'HEL', 'AMS', 'CAS', 'NYC')
('PAN', 'HEL', 'AMS', 'NYC', 'CAS')
('PAN', 'HEL', 'CAS', 'AMS', 'NYC')
('PAN', 'HEL', 'CAS', 'NYC', 'AMS')
...
..and so on

('HEL', 'NYC', 'PAN', 'CAS', 'AMS'),
 ('HEL', 'NYC', 'AMS', 'PAN', 'CAS'),
 ('HEL', 'NYC', 'AMS', 'CAS', 'PAN'),
 ('HEL', 'NYC', 'CAS', 'PAN', 'AMS'),
 ('HEL', 'NYC', 'CAS', 'AMS', 'PAN')]

As a side note, whilst your attempt was good, because the output is large and the number of recursions is large, you could get stack overflow.附带说明一下,虽然您的尝试很好,但由于 output 很大并且递归次数很大,您可能会遇到堆栈溢出。

There were two alternative things that you can do:您可以做两件事:

  • increase the limit of recursions增加递归的限制
  • transform to a while or for loop.转换为whilefor循环。

However, the itertool.permutations option is most suitable.但是, itertool.permutations选项是最合适的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM