2つの文字列をインターリーブするすべての可能な方法


21

最近、stackoverflowでこの質問を見ました。すばらしい質問ですが、この質問には致命的な問題が1つあります。彼らはそれを行うための最良の方法を求めています。たとえば、読みやすく、最も慣用的で、最近のものなど。彼らはそれが重要ではないことを知らないのですか?最小限のコードでそれを行う方法について尋ねる必要があります!

私はその質問がstackoverflowで高く評価されるとは思わないので、私はそれをここで尋ねることにしました。

チャレンジ

任意の2つの文字列をインターリーブするためのすべての可能な方法を生成する、最短のプログラムまたは関数を作成する必要があります。たとえば、2つの文字列が'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
「この素晴らしい質問を見つけました。しかし、致命的な欠陥が1つあります。
チョイス

1
「aabb」、「bc」のサンプルIOを提供する必要があります。
Taemyr

回答:


1

Pyth、26

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

ここで試してみてください

これは、指定された再帰式の非常に基本的な実装です。関数を定義しますg必要なタスクを実行をます。リンクは、STDIN改行から分離された文字列を読みやすくするために変更されたプログラムです。関数を呼び出すために行います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

2つの再帰呼び出しは非常に似ていますが、ゴルフをする方法を見つけることができませんでした。


10

Haskell、53 48バイト

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

関数%を定義しますa%b文字列で文字列a,bのリストを提供ます。

2つの文字列が与えられた場合、最初の文字を取得する2つのうちの1つを選択します。次に、2つの文字列の残りの部分を再帰処理し、各文字を各結果の先頭に追加します。

ストリングの1つが空の場合、唯一の可能な結果は他のストリングです。""%""=[""]でも十分ですが、それは長いです。


53バイト:

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

文字列%a%d持つ関数を定義しますa,dのリストを提供ます。

関数は再帰的に定義されます。最初の文字列から文字を取得する場合、最初の文字列の残りと2番目の文字列の再帰呼び出しの各結果の前に文字を追加する必要があります。他の文字列に対して対称的に。

基本ケースでは、文字列の1つが空の場合、結果はそれらの連結の単一要素リストです。これは、各文字列が空の場合の2つのケースよりも短いです。


@aditsuおっと、という意味""%""=[""]です。
-xnor

まったく同じ言語で正確に1バイトだけ答えが得られるのは奇妙です
誇りに思っているhaskeller

10

ハスケル、47

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

% この課題を解決するオペレーターです。

#は、2つのリストを取り込んで、最初の文字が最初の文字列(エッジの場合-最初のリストが空の場合、結果は空のリスト)になるようにインターリーブするすべての方法を見つける演算子です。%

その後、2回%適用するだけで機能し#ます。

編集: 前のバージョンにはバグがあり、が""%""返された["",""]ため、修正しました。にベースケースを追加することで修正され%、同じ長さのベースケースを削除できるようになりました#(実際にはあまり意味がありませんでした)。


@nimiしかし、型のミスマッチ- (#) :: [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']

2つの文字列x,yを指定すると、の最初の文字を取得してx、再帰呼び出しの各結果の先頭に追加できますf(x[1:],y)。それとも、私たちは、と同じことを行うことができますxし、y切り替えます。取ることによってx,y入力のどちらかとしてpまたはその反転`P [:: - 1]、我々は両方の可能性を取得します。

空の文字列から取得しないようにするには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])]

4バイトを食べてくれてありがとうSp3000 :)


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!です。残りは、2つの文字列からその順序で文字を単純に引き出します。


いいですね、私はその考えについて考えましたが、それはそれほどよくゴルフできるとは思いませんでした。
aditsu

@aditsuは、私たちが本当に必要なの間でミックスされe*かつ.*異なる量で各要素を繰り返しています。;)(つまり、行うべき演算子です:a.*:~e*現在2つのリストが与えられているとエラーになるので、そのために使用できると思います。)
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

オンラインでお試しください!

入力変数を介して2つの文字列のリストとして入力を受け取り、出力変数を介してすべての可能なインターリーブを生成します。テストケースは、文字が共有されている重複したインターリービングを許可するように見えるので、私はそれらを避けるために、任意の注意を払っていないが、これは発生し多くのより多くの重複だけではなく、共有の文字では。(これが許可されていないが、共有文字の重複が不要な場合は、重複のない{}ᵘリストとして出力するために3バイトを追加するだけです。)

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.

基本的に、これは両方の文字列のすべてのパーティションを生成し、通常の決定論的な方法でいずれかの順序でインターリーブします。余分な重複インターリーブは、最初の長さと2番目の長さの差が0または1以外の値であるパー​​ティションペアが原因であるため、それらの1つは、最後に互いに連結されるチャンクを持ちます。したがって、サンプル出力と同じ多重度で出力を生成するには:

Brachylog、17バイト

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

オンラインでお試しください!

余分なコード、は{lᵐ-ℕ<2&}、無関係な分割が行われるパーティションペアに失敗します。(Pythonシェルでの出力チェックを簡単にするために、TIOのヘッダーを引用符で印刷するように変更しました。)


1

MATL34 30バイト

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

これは、この答えからのアイデアを使用しています。文字列の長さがmand である場合、ビットセットでnすべてのm+nビットパターンを列挙しmます。その列挙を行う1つの方法は、1 mn0 を持つベクトルのすべての順列を生成してから、重複を削除することです。

オンラインでお試しください!

説明

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

バッチ、154 152バイト

@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%
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.