Niedawno widziałem to pytanie przy przepełnieniu stosu. To świetne pytanie, ale jest jeden poważny problem z pytaniem. Pytają o najlepszy sposób, aby to zrobić. Np. Najłatwiejszy do odczytania, najbardziej idiomatyczny, schludny itp. Czy oni nie wiedzą, że to nie ma znaczenia? Powinieneś zapytać, jak to zrobić, używając jak najmniej bajtów kodu!
Ponieważ wątpię, czy to pytanie zostanie docenione przy przepływie stosów, postanowiłem zadać je tutaj.
Wyzwanie
Musisz napisać możliwie najkrótszy program lub funkcję, która generuje wszystkie możliwe sposoby przeplatania dowolnych dwóch dowolnych ciągów. Na przykład, jeśli dwa ciągi są 'ab'
i 'cd'
, wynikiem jest:
['abcd', 'acbd', 'acdb', 'cabd', 'cadb', 'cdab']
Jak widać, a
jest zawsze wcześniej b
i c
zawsze jest wcześniej d
.
IO może mieć dowolny rozsądny format. Użyj tego kodu python, aby sprawdzić, aby sprawdzić wyniki. (kredyt: 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
Próbka 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']
Jak zwykle obowiązują standardowe luki i wygrywa najkrótsza odpowiedź w bajtach. Ponieważ pytanie pierwotnie dotyczyło Pythona, chciałbym zobaczyć najkrótszą odpowiedź na python. (I nie, pyth to nie python). Zachęca się jednak do odpowiedzi w dowolnym języku.
źródło
Odpowiedzi:
Pyth, 26
Wypróbuj tutaj
Jest to bardzo podstawowa implementacja danej formuły rekurencyjnej. Definiuje funkcję,
g
która wykonuje wymagane zadanie. Link jest zmodyfikowanym programem, który odczytuje ciągi znaków oddzielone STDIN oddzielone, dla wygody. Aby wywołać funkcję, wykonajg<string1><string2>
.Ekspansja:
Te dwa rekurencyjne połączenia są bardzo podobne, ale nie byłem w stanie znaleźć sposobu na ich grę w golfa.
źródło
Haskell,
5348 bajtówDefiniuje funkcję,
%
dla której zaa%b
pomocą łańcuchówa,b
podano listę łańcuchów.Biorąc pod uwagę dwa ciągi, wybieramy jeden z dwóch, z którego bierze się pierwszy znak. Następnie wykonujemy rekurencję na pozostałych dwóch ciągach, przygotowując ten znak do każdego wyniku.
Gdy jeden z ciągów jest pusty, jedynym możliwym wynikiem jest drugi ciąg.
""%""=[""]
wystarczyłoby, ale jest dłużej.53 bajty:
Definiuje funkcję,
%
dla której zaa%d
pomocą łańcuchówa,d
podano listę łańcuchów.Funkcja jest zdefiniowana rekurencyjnie. Jeśli weźmiemy znak z pierwszego łańcucha, to musi on być poprzedzony każdym wynikiem wywołania rekurencyjnego na pozostałym ciągu pierwszego łańcucha z drugim łańcuchem. Symetrycznie dla drugiego ciągu.
W przypadku podstawowym, jeśli jeden z ciągów jest pusty, wynikiem jest lista jednoelementowa ich konkatenacji. Jest to mniej niż dwa przypadki dla każdego ciągu pustego.
źródło
""%""=[""]
.Haskell, 47 lat
%
jest operatorem, który rozwiązuje to wyzwanie.#
jest operatorem, który pobiera dwie listy i znajduje wszystkie sposoby ich przeplatania w taki sposób, że pierwszy znak pochodzi z pierwszego łańcucha (z przypadkiem krawędzi - jeśli pierwsza lista jest pusta, to wynikiem jest pusta lista) poprzez rekurencję do%
.następnie
%
działa tylko#
dwukrotnie.Edycja: poprzednia wersja miała błąd, w którym
""%""
wróciła["",""]
, więc naprawiłem to. Zostało to naprawione przez dodanie skrzynki podstawowej%
, co pozwoliło następnie usunąć skrzynkę podstawową o tej samej długości#
(co tak naprawdę nie miało większego sensu).źródło
(#) :: [a]->[a]->[[a]]
, więca::[a]
wynik powinien być[[a]]
Python 2, 71 bajtów
Przykładowy przebieg:
Biorąc pod uwagę dwa ciągi znaków
x,y
, możemy wziąć pierwszy znakx
i dołączyć go do każdego wyniku wywołania rekurencyjnego, gdy go brakujef(x[1:],y)
. Albo możemy zrobić to samo zx
iy
włączony. Przyjmującx,y
jako wejściep
lub jego odwrócenie `p [:: - 1], otrzymujemy obie możliwości.Aby uniknąć pobrania z pustego ciągu
x
, logicznie zwarliśmy się zx and
. Jeśli oba ciągi są puste, żaden ciąg nie może być,x
a my otrzymujemy i opróżniamy listę możliwości, które naprawiamyor
w poprawnej podstawowej skrzynce['']
.Podobna strategia generatywna w Pythonie 3 (73 bajty):
źródło
Python, 80
Zgodnie z prośbą, oto odpowiedź python:
Dzięki Sp3000 za zjedzenie 4 bajtów :)
źródło
CJam, 38 lat
Wypróbuj online
Programowanie dynamiczne (z wykorzystaniem zapamiętanej rekurencji).
Wyjaśnienie:
źródło
CJam, 32 bajty
Sprawdź to tutaj.
To naprawdę gra w golfa, ale do tej pory znalazłem tylko 4 alternatywne rozwiązania, z których wszystkie mają tę samą liczbę bajtów:
Podstawową ideą jest wygenerowanie wszystkich permutacji
0
si i1
s odpowiadających ciągowi znaków, z którego ma wynikać każdy znak. To wszystko do włączniee!
. Reszta po prostu wyciąga znaki w tej kolejności z dwóch ciągów.źródło
e*
i.*
która powtarza każdy element w innej ilości. ;) (To znaczy operator do zrobienia:a.*:~
. Podejrzewam, żee*
może być do tego użyty, ponieważ obecnie zawiera błędy, jeśli otrzyma dwie listy.)JavaScript (Firefox 30-57),
888481 bajtówEdycja: Zapisano 4 bajty, poprawiając mój warunek zakończenia. Zaoszczędzono 3 bajty dzięki @ edc65.
źródło
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))
v
jako warunku, ale nigdy nie przyszło mi to do głowyv[1]
.Brachylog , 8 bajtów
Wypróbuj online!
Pobiera dane wejściowe jako listę dwóch łańcuchów poprzez zmienną wejściową i generuje wszystkie możliwe przeploty poprzez zmienną wyjściową. Ponieważ przypadki testowe wydają się zezwalać na duplikaty przeplotów w przypadku wspólnych liter, nie starałem się ich unikać, ale generuje to o wiele więcej duplikatów, a nie tylko wspólnych liter. (Jeśli nie jest to dozwolone, ale duplikaty udostępnionych liter nie są konieczne, po prostu dodaj trzy bajty, aby zawinąć w
{}ᵘ
celu uzyskania jako listy bez duplikatów.)Zasadniczo generuje to każdą partycję obu łańcuchów, a następnie przeplata je w normalny deterministyczny sposób w dowolnej kolejności. Dodatkowe duplikaty przeplatania są spowodowane parami podziału, w których różnica między długością pierwszego i długością drugiego ma pewną wartość inną niż 0 lub 1, tak że jeden z nich ma fragmenty, które na końcu łączą się ze sobą. Tak więc, aby uzyskać dane wyjściowe o takich samych krotnościach jak dane wyjściowe próbki:
Brachylog , 17 bajtów
Wypróbuj online!
Dodatkowy kod
{lᵐ-ℕ<2&}
nie działa na żadnej parze partycji, w której są tworzone podziały zewnętrzne. (Zmieniłem nagłówek w TIO, aby drukować z cudzysłowami, aby ułatwić sprawdzanie wyników w powłoce Pythona.)źródło
MATL ,
3430 bajtówWykorzystuje to pomysł z tej odpowiedzi : jeśli długości ciągów są
m
in
, wylicz wszystkiem+n
wzorcem
bitów z ustawionymi bitami. Jednym ze sposobów wykonania tego wyliczenia jest: wygenerowanie wszystkich permutacji wektora za pomocą zer im
jedynek,n
a następnie usunięcie duplikatów.Wypróbuj online!
Wyjaśnienie
źródło
Rubinowy, 83 bajty
Funkcja rekurencyjna, która zwraca,
[a+b]
jeśli którykolwiek z tych ciągów jest pusty. W przeciwnym razie zwraca listę ciągówa[0] + every string in v[a[1..-1],b]
dodanych do listy ciągówb[0] + every string in v[a,b[1..-1]]
źródło
Partia,
154152 bajtówźródło