Tutti i modi possibili per interlacciare due stringhe


21

Di recente ho visto questa domanda su StackOverflow. È un'ottima domanda, ma c'è un problema fatale con la domanda. Stanno chiedendo il modo migliore per farlo. Ad esempio, più facile da leggere, più idiomatico, più pulito ecc. Non sanno che non è quello che conta? Dovresti chiedere come farlo con il minor numero di byte di codice!

Dal momento che dubito che questa domanda sarà apprezzata su StackOverflow, ho deciso di porla qui.

La sfida

È necessario scrivere il programma o la funzione più breve possibile che generi tutti i modi possibili per intercalare due stringhe arbitrarie. Ad esempio, se le due stringhe sono 'ab'e 'cd', l'output è:

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

Come puoi vedere, aè sempre prima bed cè sempre prima d.

IO può essere in qualsiasi formato ragionevole. Usa questo codice Python per verificare il tuo output. (credito: 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 di esempio:

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']

Come al solito, si applicano scappatoie standard e vince la risposta più breve in byte. Poiché la domanda era originariamente su Python, mi piacerebbe vedere la risposta più breve di Python. (E no, pyth non è python). Tuttavia, le risposte in qualsiasi lingua sono incoraggiate.


5
Il minor numero di byte di codice è il modo migliore per farlo, lo sanno tutti! * (Disclaimer: non CR).
Rɪᴋᴇʀ

1
Tutti i personaggi sono distinti? O non necessariamente?
aditsu,

4
In realtà ... nel tuo esempio di "codice", "golf" hai una "o" duplicata e anche risultati duplicati, ad esempio "gcoodelf". Presumo sia quello che vuoi.
aditsu,

1
"Ho appena trovato questa grande domanda. Tuttavia, c'è un difetto fatale: lo vogliono fatto bene!"
Cyoce,

1
È necessario fornire l'IO di esempio per "aabb", "bc".
Taemyr,

Risposte:


1

Pyth, 26

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

Provalo qui

Questa è un'implementazione di base della formula ricorsiva data. Definisce una funzione gche esegue l'attività richiesta. Il collegamento è un programma modificato che legge le stringhe da newline STDIN separate, per essere più conveniente. Per chiamare la funzione do g<string1><string2>.

Espansione:

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

Le due chiamate ricorsive sono molto simili, ma non sono più riuscito a trovare il modo di giocarle.


10

Haskell, 53 48 byte

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

Definisce una funzione %per la quale a%bcon le stringhe a,bviene visualizzato un elenco di stringhe.

Date due stringhe, scegliamo una delle due da cui prendere il primo personaggio. Quindi ricerchiamo il resto di due stringhe, anteponendo quel carattere a ciascun risultato.

Quando una delle stringhe è vuota, l'unico risultato possibile è l'altra stringa. ""%""=[""]basterebbe anche, ma è più lungo.


53 byte:

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

Definisce una funzione %per la quale a%dcon le stringhe a,dviene visualizzato un elenco di stringhe.

La funzione è definita in modo ricorsivo. Se prendiamo un carattere dalla prima stringa, allora deve essere anteposto a ciascun risultato della chiamata ricorsiva sul rimanente della prima stringa con la seconda stringa. Simmetricamente per l'altra stringa.

Nel caso di base, se una delle stringhe è vuota, il risultato è un elenco a singolo elemento della loro concatenazione. Questo è più breve di due casi per ogni stringa vuota.


@aditsu Oops, intendevo ""%""=[""].
xnor

È strano avere una risposta che ti conquista esattamente di un byte nella stessa lingua
orgoglioso haskeller il

10

Haskell, 47

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

% è l'operatore che risolve questa sfida.

#è un operatore che prende in due elenchi e trova tutti i modi per interfogliarli in modo tale che il primo carattere provenga dalla prima stringa (con un maiuscolo - se il primo elenco è vuoto, il risultato è un elenco vuoto) ricorrendo a %.

quindi %funziona semplicemente applicando #due volte.

Modifica: la versione precedente aveva un bug in cui era ""%""tornata ["",""], quindi l'ho risolto. È stato risolto aggiungendo un caso base a %, che poi ha permesso di rimuovere un caso base della stessa lunghezza #(che in realtà non aveva molto senso).


@nimi Ma i tipi non corrispondono - (#) :: [a]->[a]->[[a]], quindi a::[a]e il risultato dovrebbe essere di tipo[[a]]
orgoglioso haskeller il

Oops, hai ragione. Scusate.
nimi

8

Python 2, 71 byte

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

Esempio di esecuzione:

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

Date due stringhe x,ypossiamo prendere il primo carattere di xe anteporre a ciascun risultato della chiamata ricorsiva mancante f(x[1:],y). Oppure, possiamo fare lo stesso con xe ycambiato. Prendendo x,ycome input po la sua inversione `p [:: - 1], otteniamo entrambe le possibilità.

Per evitare di prendere da una stringa vuota x, abbiamo un cortocircuito logico con x and. Se entrambe le stringhe sono vuote, nessuna stringa può esserlo xe otteniamo un elenco di possibilità vuoto, che risolviamo con oril caso base corretto [''].

Una strategia generativa simile in Python 3 (73 byte):

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

Che tipo di stregoneria è questa?! (+1)
aditsu,

3

Python, 80

Come richiesto, ecco una risposta 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])]

Grazie Sp3000 per aver mangiato 4 byte :)


2

CJam, 38

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

Provalo online

Programmazione dinamica (utilizzando la ricorsione memorizzata).

Spiegazione:

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 byte

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

Provalo qui.

Sembra davvero giocabile a golf, ma finora ho trovato solo 4 soluzioni alternative che hanno tutte lo stesso numero di byte:

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)

L'idea di base è quella di generare tutte le permutazioni di 0s e 1S corrispondente al quale stringa di prendere ogni carattere nel risultato. Questo è tutto fino a, incluso il e!. Il resto estrae semplicemente i caratteri in quell'ordine dalle due stringhe allora.


Bello, ho pensato a quell'idea, ma non pensavo che potesse golf così bene.
aditsu,

@aditsu Ciò di cui abbiamo davvero bisogno è un mix tra e*e .*che ripete ogni elemento di una quantità diversa. ;) (Vale a dire un operatore da fare :a.*:~. Suppongo che e*potrebbe essere usato per questo dato che al momento errori se dati due elenchi.)
Martin Ender

2

JavaScript (Firefox 30-57), 88 84 81 byte

(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)]

Modifica: salvato 4 byte migliorando la mia condizione di terminazione. Salvato 3 byte grazie a @ edc65.


Troppo vicino alla pubblicazione, ma dai un'occhiata - è più breve: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 Molto bello; Avevo provato e non ero riuscito a usare vcome condizione, ma non mi era mai venuto in mente di usarlo v[1].
Neil,

2

Brachylog , 8 byte

p~cᵐz₁cc

Provalo online!

Prende l'input come un elenco di due stringhe attraverso la variabile di input e genera tutti i possibili intrecci attraverso la variabile di output. Poiché i casi di test sembrano consentire duplicati intrecci in cui vi sono lettere condivise, non mi sono preoccupato di evitarli, ma questo genera molti più duplicati e non solo con lettere condivise. (Se ciò non è consentito, ma i duplicati delle lettere condivise non sono necessari, basta aggiungere tre byte da racchiudere {}ᵘper l'output come elenco senza duplicati.)

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.

In sostanza, questo genera ogni partizione di entrambe le stringhe, quindi le interleade nel normale modo deterministico in entrambi gli ordini. Le intrecci duplicati extra sono dovuti a coppie di partizioni in cui la differenza tra la lunghezza del primo e la lunghezza del secondo ha un valore diverso da 0 o 1, in modo che uno di essi abbia blocchi che si concatenano alla fine. Quindi, per produrre output con le stesse molteplicità dell'output di esempio:

Brachylog , 17 byte

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

Provalo online!

Il codice aggiuntivo {lᵐ-ℕ<2&}, non riesce a qualsiasi coppia di partizioni in cui vengono create divisioni estranee. (Ho modificato l'intestazione su TIO per stampare con virgolette per un più facile controllo dell'output nella shell Python.)


1

MATL , 34 30 byte

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

Questo utilizza un'idea da questa risposta : se le lunghezze delle stringhe sono me n, enumera tutti i m+nmodelli di mbit con i bit impostati. Un modo per farlo è quell'enumerazione: generare tutte le permutazioni di un vettore con muno e nzeri e quindi rimuovere i duplicati.

Provalo online!

Spiegazione

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

Rubino, 83 byte

Una funzione ricorsiva che ritorna [a+b]se una di queste stringhe è vuota. Altrimenti, restituisce un elenco di stringhe a[0] + every string in v[a[1..-1],b]aggiunte a un elenco di stringheb[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

Lotto, 154 152 byte

@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%
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.