交织两个字符串的所有可能方法


21

我最近在stackoverflow上看到了这个问题。这是一个很好的问题,但是这个问题有一个致命的问题。他们正在寻求最佳方法。例如,最容易阅读,最惯用,最整洁等。他们不知道这并不重要吗?您应该问如何用最少的代码字节来做!

因为我怀疑这个问题会在stackoverflow上得到赞赏,所以我决定在这里提问。

挑战

您必须编写最短的程序或函数,以生成所有可能的方式来交织任意两个任意字符串。例如,如果两个字符串是'ab''cd',则输出为:

['abcd', 'acbd', 'acdb', 'cabd', 'cadb', 'cdab']

如您所见,a总是在b,并且c总是在d

IO可以采用任何合理的格式。使用此python代码进行验证以检查您的输出。(信用:JeD

def shuffle(s,t):
    if s=="":
        return [t]
    elif t=="":
        return [s]
    else:
        leftShuffle=[s[0]+val for val in shuffle(s[1:],t)]
        rightShuffle=[t[0]+val for val in shuffle(s,t[1:])]
        leftShuffle.extend(rightShuffle)
        return leftShuffle

样本IO:

shuffle("$", "1234"):
['$1234', '1$234', '12$34', '123$4', '1234$']

shuffle("az", "by"):
['azby', 'abzy', 'abyz', 'bazy', 'bayz', 'byaz']

shuffle("code", "golf"):
['codegolf', 'codgeolf', 'codgoelf', 'codgolef', 'codgolfe', 'cogdeolf', 'cogdoelf',
'cogdolef', 'cogdolfe', 'cogodelf', 'cogodlef', 'cogodlfe', 'cogoldef', 'cogoldfe',
'cogolfde', 'cgodeolf', 'cgodoelf', 'cgodolef', 'cgodolfe', 'cgoodelf', 'cgoodlef',
'cgoodlfe', 'cgooldef', 'cgooldfe', 'cgoolfde', 'cgoodelf', 'cgoodlef', 'cgoodlfe',
'cgooldef', 'cgooldfe', 'cgoolfde', 'cgolodef', 'cgolodfe', 'cgolofde', 'cgolfode',
'gcodeolf', 'gcodoelf', 'gcodolef', 'gcodolfe', 'gcoodelf', 'gcoodlef', 'gcoodlfe',
'gcooldef', 'gcooldfe', 'gcoolfde', 'gcoodelf', 'gcoodlef', 'gcoodlfe', 'gcooldef',
'gcooldfe', 'gcoolfde', 'gcolodef', 'gcolodfe', 'gcolofde', 'gcolfode', 'gocodelf',
'gocodlef', 'gocodlfe', 'gocoldef', 'gocoldfe', 'gocolfde', 'goclodef', 'goclodfe',
'goclofde', 'goclfode', 'golcodef', 'golcodfe', 'golcofde', 'golcfode', 'golfcode']

像往常一样,存在标准漏洞,而最短的答案以字节为单位。由于问题最初是关于python的,所以我希望看到最短的python答案。(不,pyth不是python)。但是,鼓励使用任何语言的答案。


5
最少的代码字节执行此操作的最佳方法,每个人都知道!*(免责声明:不是CR)。
Rɪᴋᴇʀ

1
所有字符都不同吗?还是不一定?
aditsu

4
实际上,在您的“代码”,“高尔夫”示例中,您有一个重复的“ o”并且也有重复的结果,例如“ gcoodelf”。我假设这就是您想要的。
aditsu

1
“我刚刚发现了这个大问题。但是,有一个致命的缺陷:他们希望它做得好!”
Cyoce

1
您应该为“ aabb”,“ bc”提供示例IO。
Taemyr '16

Answers:


1

佩斯,26

M?G?H++LhGgtGH+LhHgGtH]G]H

在这里尝试

这是给定递归公式的非常基本的实现。它定义了g执行所需任务的功能。该链接是经过修改的程序,可以从STDIN换行符中读取字符串,以便更加方便。调用函数do g<string1><string2>

扩张:

M                ##  Define a function g taking two arguments: G and H
 ?G?H ... ]G]H   ##  Two ternaries: if G is empty return a list containing H
                 ##  if H is empty return a list containing G
   +             ##  otherwise return these next two lists joined together
   +LhGgtGH      ##  the first letter of G added to each result of a recursive call to g
                 ##  with G missing its first character and H
   +LhHgGtH      ##  the same as above but with G and H swapped

这两个递归调用非常相似,但是我再也找不到找到高尔夫的方法了。


10

Haskell,53个48字节

a%""=[a]
a%b=[x:t|(x:y,z)<-[(a,b),(b,a)],t<-y%z]

定义一个函数%,该函数的a%b字符串a,b提供字符串列表。

给定两个字符串,我们选择两个字符串中的一个作为第一个字符。然后,我们递归处理两个字符串的其余部分,然后将该字符放在每个结果之前。

当一个字符串为空时,唯一可能的结果是另一个字符串。""%""=[""]也足够,但是更长。


53个字节:

a@(b:c)%d@(e:f)=((b:)<$>c%d)++((e:)<$>a%f)
a%d=[a++d]

定义一个函数%,该函数的a%d字符串a,d提供字符串列表。

该函数是递归定义的。如果我们从第一个字符串中提取一个字符,则必须在第一个字符串的其余部分和第二个字符串之前,将其放在递归调用的每个结果之前。对称地表示另一个字符串。

对于基本情况,如果字符串之一为空,则结果是它们的串联的单元素列表。对于每个字符串为空的情况,这比两种情况短。


@aditsu糟糕,我是说""%""=[""]
xnor

有一个答案用一种完全相同的语言赢了您一个字节,这很奇怪
骄傲的haskeller

10

哈斯克尔,47岁

(x:s)#b=(x:)<$>s%b
a#b=[]
[]%b=[b]
a%b=a#b++b#a

% 是解决这一挑战的运营商。

#是一个运算符,它接受两个列表,并找到所有交错方式,以使第一个字符来自第一个字符串(带有边沿大小写-如果第一个列表为空,则结果为空列表),方法是递归至%

然后,%只需应用#两次即可。

编辑: 以前的版本有一个bug,其中""%""返回["",""],所以我将其修复。通过在中添加一个基本案例来修复%该问题,然后再从中删除相同长度的基本案例#(这实际上没有多大意义)。


@nimi但是类型为mismach- (#) :: [a]->[a]->[[a]],所以a::[a]结果应该为类型[[a]]
骄傲的haskeller

糟糕,您是对的。抱歉。
nimi

8

Python 2,71个字节

f=lambda*p:[x[0]+t for x,y in p,p[::-1]for t in x and f(x[1:],y)]or['']

示例运行:

>> f('ab','AB')
['abAB', 'aABb', 'aAbB', 'ABab', 'AabB', 'AaBb']

给定两个字符串,x,y我们可以采用的第一个字符,x并将其添加到递归调用的每个结果之前,并使其丢失f(x[1:],y)。或者,我们可以做同样的xy切换。通过将p [::-1] x,y作为其输入p或取反,我们得到了两种可能性。

为了避免取空字符串x,我们使用进行逻辑短路x and。如果两个字符串都为空,则两个字符串都不可以,x并且我们获得的可能性列表为空,我们将其固定or为正确的基本情况['']

Python 3中类似的生成策略(73字节):

f=lambda p,s='':[f((x[1:],y),s+x[0])for x,y in[p,p[::-1]]if x]or print(s)

这是什么魔法?!(+1)
aditsu

3

Python,80岁

根据要求,这是一个python答案:

f=lambda a,b,c='':[c+x for x in[a+b][a>''<b:]or f(a[1:],b,a[0])+f(a,b[1:],b[0])]

感谢Sp3000吃了4个字节:)


2

CJam,38岁

q~L{_2$e&{_2$(\@jf+@@(@@jf++}{+a}?}2jp

在线尝试

动态编程(使用记忆式递归)。

说明:

q~         read and evaluate the input (2 strings)
L{…}2j     calculate with memoized recursion with no initial cache and 2 arguments
  _2$      copy the 2 strings
  e&{…}    if they are both non-empty
    _2$    copy the strings again (they're in reverse order)
    (      take out the first character of the first string
    \@     move the strings after the character
    j      solve recursively
    f+     prepend the character to all results
    @@     bring the other copy of the strings on top (in order)
    (      take out the first character of the second string
    @@     move the strings after the character
    j      solve recursively
    f+     prepend the character to all results
    +      concatenate the 2 sets of results
  {…}      else
    +      concatenate the 2 strings (at least one is empty)
    a      put the result in an array
  ?        end if
p          pretty-print the results for the input strings

2

CJam,32个字节

qN/_:,eeWf%e~e!\f{\{_2$=(ot}/No}

在这里测试。

这听起来真的很不错,但是到目前为止,我只发现了4个具有相同字节数的替代解决方案:

qN/_ee{),*~}%e!\f{\{_2$=(ot}/No}
l_:!l_0f>@+])e!\f{\{_2$=(ot}/No}
ll__3$:!+.=])e!\f{\{_2$=(ot}/No}
qN/[_:,2,]ze~e!\f{\{_2$=(ot}/No} (found by Sp3000)

基本思想是生成0s和1s的所有排列,对应于从结果中获取每个字符的字符串。包括在内的所有内容e!。剩下的只是简单地按顺序从两个字符串中提取字符。


很好,我想到了这个主意,但认为打高尔夫球没那么好。
aditsu

@aditsu我们真正需要的是之间的混合,e*.*以不同的数量重复每个元素。;)(即操作员要做的:a.*:~。我想e*可以用于此操作,因为如果给出两个列表,它当前会出错。)
Martin Ender

2

JavaScript(Firefox 30-57),88 84 81字节

(s,t,g=(v,w)=>v[1]?f(v.slice(1),w).map(x=>v[0]+x):[v+w])=>[...g(s,t),...g(t,s)]

编辑:通过改善我的终止条件保存了4个字节。@ edc65,节省了3个字节。


太接近发布了,但是看看-更短了:f=(a,b,z=(v,w)=>v[1]?f(v.slice(1),w).map(x=>v[0]+x):[v+w])=>z(a,b).concat(z(b,a))
edc65

@ edc65非常好;我尝试过并以失败告终v,但我从来没有想到要使用v[1]
尼尔

2

Brachylog,8个字节

p~cᵐz₁cc

在线尝试!

通过输入变量将输入作为两个字符串的列表,并通过输出变量生成所有可能的交织。由于测试案例似乎允许凡有共用的字母重复的交错,我没有采取任何照顾,以避免它们,但它产生的大量的多个副本,而不仅仅是共享信。(如果不允许这样做,但是不需要共享字母重复,只需添加三个字节即可换行以{}ᵘ作为没有重复的列表输出。)

p           A permutation of
            the input variable
   ᵐ        with each element
 ~c         arbitrarily partitioned,
    z       zipped
     ₁      without cycling,
      cc    and concatenated twice
            is the output variable.

本质上,这将生成两个字符串的每个分区,然后以正常的确定性方式以任一顺序对它们进行交织。额外的重复交织是由于分区对造成的,分区对中第一个的长度和第二个的长度之间的差值为0或1以外的值,因此其中一个具有在末尾彼此串联的块。因此,要产生具有与样本输出相同的多重性的输出:

Brachylog,17个字节

p~cᵐ{lᵐ-ℕ<2&}z₁cc

在线尝试!

多余的代码{lᵐ-ℕ<2&}会使进行任何无关划分的任何分区对失败。(我更改了TIO上的标头以使用引号打印,以便在Python shell中更容易地检查输出。)


1

MATL34 30字节

h1Mgw~hY@Xu!ttYs*w~tYs1Gn+*+!)

这使用了这个答案中的一个想法:如果字符串的长度是mn,则枚举所有设置m+nm位的位模式。进行枚举的一种方法是:生成一个向量的所有排列,该排列带有一mn零,然后删除重复项。

在线尝试!

说明

h     % implicitly input the two strings of lengths m and n. Concatenate
1M    % push the two strings again
g     % convert the second strings into ones
w~    % swap. Convert the second string into zeros
h     % concatenate: vector of zeros and ones
Y@    % 2D array with all permutations of that vector, each on a row
Xu    % remove duplicate rows
!     % transpose
ttYs  % duplicate twice. Cumulative sum along each column
*     % element-wise product. Produces, in each column, indices for
      % elements of the first string; 1, 2,...,m. The rest are 0
w~    % swap, negate
tYs   % duplicate. Cumulative sum along each column
1Gn+  % add length of first input
*     % element-wise product. Produces, in each column, indices for
      % elements of the second string: m+1,...,m+n. The rest are 0
+     % add. This gives indices into the concatenated string created initially
!     % transpose back
)     % index into concatenated string. Implicitly display

0

Ruby,83个字节

[a+b]如果这些字符串中的任何一个为空,则返回一个递归函数。否则,它返回a[0] + every string in v[a[1..-1],b]添加到字符串列表的字符串列表b[0] + every string in v[a,b[1..-1]]

v=->a,b{a[0]&&b[0]?v[a[1..-1],b].map{|i|a[0]+i}+v[a,b[1..-1]].map{|i|b[0]+i}:[a+b]}

0

批处理,154152字节

@if "%~1%~2"=="" echo %3
@set t=%~1
@if not "%t%"=="" call %0 "%t:~1%" "%~2" %3%t:~,1%
@set t=%~2
@if not "%t%"=="" call %0 "%~1" "%t:~1%" %3%t:~,1%
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.