简体   繁体   English

排列维持某些元素的顺序

[英]Permutations maintaining order of some elements

Looking for an implementation in Python but I can probably translate from anything. 寻找Python的实现,但我可以从任何东西翻译。

If I have the string "cats " , which is the word cats followed by four spaces, how can I find all of the possible permutations that maintain the order of the word cats . 如果我有string "cats " ,这是单词cats后跟四个空格,我怎样才能找到维持单词cat的顺序的所有可能的排列。 That is I'm not looking for any permutations where a is the first actual letter, or t, etc., but instead all of the possible arrangements of white space in between the letters in cats . 那就是我不是在寻找任何排列,其中a是第一个实际的字母,或者等等,而是cats的字母之间所有可能的白色空间排列。

Some examples: 一些例子:

"cats    "
"c ats   "
"  cat  s"
"c a t s "
" c a t s"

This is a solution, not an algorithm :) The algorithm is buried in the implementation of itertools.combinations (but see below for an implementation without builtin library functions). 这是一个解决方案,而不是算法:)该算法隐藏在itertools.combinations的实现中(但请参见下面的没有内置库函数的实现)。

from functools import reduce
from itertools import combinations

def assign(v, p):
  v[p[0]] = p[1]
  return v

def interp(word, letter, size):
  return (''.join(reduce(assign, zip(comb, word), [letter] * size))
          for comb in combinations(range(size), len(word)))

Example (using dots instead of spaces to make them more visible): 示例(使用点而不是空格使其更加明显):

>>> print('\n'.join(interp("cats", ".", 6)))
cats..
cat.s.
cat..s
ca.ts.
ca.t.s
ca..ts
c.ats.
c.at.s
c.a.ts
c..ats
.cats.
.cat.s
.ca.ts
.c.ats
..cats

It's actually pretty easy to implement combinations (but why bother, since it is already defined?). 它实际上很容易实现combinations (但为什么还要麻烦,因为它已经定义了?)。 Here's one solution which does way too much tuple concatenation to be efficient, but demonstrates the algorithm: 这里有一个解决方案,它实现了太多的元组连接以提高效率,但演示了算法:

def combs(vec, count, start=0):
  if count == 0:
    yield ()
  else:
    for i in range(start, len(vec) + 1 - count):
      for c in combs(vec, count - 1, i + 1):
        yield((i,) + c)

In other words, for each possible first position, choose that and complete the combination with the remaining positions. 换句话说,对于每个可能的第一个位置,选择该位置并完成与剩余位置的组合。 Similarly, you could directly implement the desired function: 同样,您可以直接实现所需的功能:

def interp(word, letter, size):
  if len(word) == 0:
    yield letter * size
  else:
    for i in range(size + 1 - len(word)):
      for comb in interp(word[1:], letter, size - i - 1):
        yield letter * i + word[0] + comb

You can create the combinations where the 4 letters should be quite easily - with combinations from the itertools module. 您可以使用itertools模块的组合创建4个字母应该非常容易的combinations

from itertools import combinations

for comb in combinations(range(len("cats    ")), len("cats")):
    # comb is a 4 tuple containing the indices where to insert the letters "cats".

Then you simply need to insert them at the correct place and join it: 然后你只需要将它们插入正确的位置并加入它:

empty = [" "]*len("cats    ")

for comb in combinations(range(len("cats    ")), len("cats")):
    newstring = list(empty)  # make a copy
    for idx, letter in zip(comb, "cats"):  # insert the letters
        newstring[idx] = letter
    print(''.join(newstring))  # join and print

cats    
cat s   
cat  s  
cat   s 
cat    s
ca ts   
ca t s  
ca t  s 
ca t   s
ca  ts  
ca  t s 
ca  t  s
[...]

You can use recursion. 你可以使用递归。

If you have n spaces, first choose how many spaces come before the first letter. 如果您有n空格,请首先选择第一个字母前面有多少个空格。 Call it k . 叫它k Then call your function with nk spaces and the remaining letters. 然后用nk空格和剩余的字母调用你的函数。

For string "cats" you have five places to insert spaces (before, after and between letters). 对于字符串“cats”,您有五个位置可以插入空格(字母之前,之后和之间)。 Essentially this is problem of generation of all integer partitions of number 4 into 5 integer parts, including zero parts. 本质上,这是将4号的所有整数分区生成为5个整数部分的问题,包括零部分。

On of the simplest methods to generate such partitions is recursive: at every level of recursion insert space into the current placeholder, and call next level, and call next level without inderting (of possible) 生成此类分区的最简单方法是递归的:在每个递归级别将空间插入当前占位符,并调用下一级,并调用下一级而不进行(可能)

Wouldn't this work? 这不行吗? It's not an algorithm but it should serve your purpose: 它不是算法,但它应该符合您的目的:

def check_word(word):
    if word.replace(" ", "") == "cats":
        return True

    return False

If you find the permutations, you can filter them out by regex: 如果找到排列,可以通过正则表达式过滤掉它们:

import itertools
import re

string = 'cats    '
pattern = ' *c *a *t *s *'
matcher = re.compile(pattern)

perms = itertools.permutations(string)
se = set([''.join(p) for p in perms])
li = list(filter(matcher.search, se))

Prints: 打印:

['   cats ',
 'c a t  s',
 'ca  t  s',
   ....
 'c   ats ',
 '  ca ts ',
 ' ca t  s',
 ' c at s ',
 'ca t   s',
 'ca  ts  ']
import itertools
str_in = "cats   "
str_in_nospace = str_in.replace(" ", "")
p = itertools.permutations(str_in, r=None)
for itm in p:
    str_curent = ''.join(itm)
    str_curent_nospace = str_curent.replace(" ", "")
    if str_curent_nospace == str_in_nospace:
        print str_curent

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

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