La stringa X è una sottosequenza della stringa Y?


23

Date le stringhe X e Y, determinare se X è una sottosequenza di Y. La stringa vuota è considerata una sottosequenza di ogni stringa. (Ad esempio, ''e 'anna'sono sottosequenze di 'banana'.)

Ingresso

  • X, una stringa alfanumerica maiuscola / minuscola eventualmente vuota
  • Y, una stringa alfanumerica maiuscola / minuscola probabilmente vuota

Produzione

  • Vero o falso (o equivalenti), che indica correttamente se X è una sottosequenza di Y.

Esempi di I / O

X      Y        output

''     'z00'    True
'z00'  'z00'    True 
'z00'  '00z0'   False
'aa'   'anna'   True
'anna' 'banana' True
'Anna' 'banana' False

criteri

  • Vince il programma più breve, determinato dal numero di byte del codice sorgente.

Programmi di esempio

  • Diversi programmi che potrebbero essere adattati sono in questo post relativo .

1
Perché il substrato "anna" di "banana"?
kaoD

4
@kaoD - annaè una sottosequenza (ma non è una sottostringa) di banana. La stringa X è una sottosequenza della stringa Y proprio se X può essere ottenuto da Y cancellando zero o più degli elementi di Y; ad esempio, l'eliminazione di be il secondo ada bananaanna.
res

2
Questo ha circa un'unica soluzione in ogni linguaggio di scripting che offre regex che è al contempo banale da vedere e impossibile da golf ulteriormente.
Joey,

Risposte:


18

Perl 5 , 17 byte (+1?), Programma completo

s//.*/g;$_=<>=~$_

Provalo online!

Richiamare con la pbandiera per l'interprete perl, come in perl -pe 's//.*/g;$_=<>=~$_'. Secondo le regole di punteggio stabilite quando questa sfida è stata originariamente pubblicata , questo flag costa un byte in più. In base alle regole più recenti , AFAICT, potrebbe essere gratuito.

In entrambi i casi, le stringhe di input devono essere fornite su linee separate con terminazione di nuova riga su stdin. L'output (su stdout) sarà 1se la prima stringa di input è una sottostringa della seconda, o niente se non lo è.

Si noti che entrambe le righe di input devono avere una riga alla fine, altrimenti il ​​programma non funzionerà correttamente. In alternativa, è possibile aggiungere il lflag della riga di comando all'invocazione per fare in modo che perl rimuova le righe; a seconda delle regole di punteggio in vigore, ciò può o non può costare un byte in più. Si noti che l'uso di questo flag aggiungerà anche una nuova riga all'output.

Versione originale (snippet, 18 byte / caratteri)

$x=~s//.*/g,$y=~$x

L'input è dato nelle variabili $xe $y, il risultato è il valore dell'espressione (nel contesto scalare). Si noti che $xviene modificato nel processo. (Sì, so che usare $_invece di $xmi permetterebbe di salvare quattro caratteri, ma farlo in uno snippet che sembra un po 'troppo sdolcinato per me.)

Come funziona?

La prima parte, $x=~s//.*/ginserisce la stringa .*tra ogni carattere in $x. La seconda parte, $y=~$xtratta $xcome una regexp e combacia $ycontro di essa. In Perl regexps, .*corrisponde a zero o più caratteri arbitrari, mentre tutti i caratteri alfanumerici si adattano comodamente a se stessi.


Secondo il nostro (nuovo?) Consenso, i contributi devono essere un programma o una funzione, non frammenti. Se la tua richiesta non ti soddisfa, considera di modificarla.
user202729

@ user202729: Questa sfida è molto più antica di quel consenso, quindi a meno che non si presuma che si applichi retroattivamente, le risposte in questo thread dovrebbero probabilmente essere "nonne". Detto questo, ho appena aggiunto una versione conforme alle regole attuali e può anche essere più breve di un byte / carattere (si noti che il conteggio basato su byte è anche più recente di questa sfida, AFAIK) a seconda di come si contano le opzioni della riga di comando.
Ilmari Karonen,

9

Rubino, 32 caratteri

s=->x,y{y=~/#{[*x.chars]*".*"}/}

Questa soluzione restituisce nilse xnon è una sottosequenza di ye un numero altrimenti (cioè ruby ​​equivalenti a falsee true). Esempi:

p s['','z00']        # => 0   (i.e. true)
p s['z00','z00']     # => 0   (i.e. true)
p s['z00','00z0']    # => nil (i.e. false)
p s['anna','banana'] # => 1   (i.e. true)
p s['Anna','banana'] # => nil (i.e. false)

1
ho praticamente fatto la stessa cosa, ma è troppo simile quindi non lo pubblicherò. penso che sia accettabile lasciare la lambda, che ti lascerebbe con y=~/#{[*x.chars]*".*"}/(23 caratteri). Saluti!
Patrick Oscity,

1
o anche y=~/#{x.split("")*".*"}/(21 caratteri) :)
Patrick Oscity,

@padde Quello diviso è in realtà 24 caratteri.
Howard,

1
scusate, immagino di aver lasciato per sbaglio accidentalmente y=~mentre giocavo con questo in irb ...
Patrick Oscity,

La mia versione è più corta di 2 caratteri.
Hauleth,

7

Haskell, 51 37

h@(f:l)%(g:m)=f==g&&l%m||h%m;x%y=x<=y

Grazie a Hammar per il sostanziale miglioramento. Ora è una funzione infix, ma non sembra esserci alcun motivo per cui non dovrebbe.

Dimostrazione:

GHCi> :{
GHCi| zipWith (%) [""   , "z00", "z00" , "anna"  , "Anna"]
GHCi|             ["z00", "z00", "00z0", "banana", "banana"]
GHCi| :}
[True,True,False,True,False]

Poiché l'elenco vuoto è più piccolo di qualsiasi altro elenco, è possibile semplificare i casi di base s x y=x<=y. Inoltre, puoi salvarne un po 'di più rendendolo un operatore e usando un @modello invece di (f:l). Questo lo riduce a 37 caratteri:h@(f:l)%(g:m)=f==g&&l%m||h%m;x%y=x<=y
Hammar

6

Python (48 caratteri)

import re;s=lambda x,y:re.search('.*'.join(x),y)

Stesso approccio della risposta di Ruby di Howard. Peccato per la necessità di Python di importare il pacchetto regex e il suo "verbose" lambda. :-)


1
Sono d'accordo, lambda è prolisso.
CalculatorFeline

4

Python, 59 caratteri

def s(x,y):
 for c in y:
  if x:x=x[c==x[0]:]
 return x==""

Ho pensato che la mia risposta sarebbe stata espressa meglio in Python.

Modifica: aggiunti i suggerimenti di res.


Sicuramente dato x="a"e y="ab"vorresti uscire dal ciclo con y=="b"e tornare false?
Peter Taylor,

@PeterTaylor Sì, ho notato che quando ho girato gli esempi di test dopo la pubblicazione che ho mescolato xe yin su. Nelle mie funzioni ydeve essere una sottosequenza di x. Penso che sarebbe meglio cambiarli per evitare confusione.
Gareth,

È possibile ottenere questo fino a 59 caratteri: def s(x,y): for c in y: if x:x=x[c==x[0]:] return x=="". Non viene visualizzato correttamente in un commento, ma penso che tu possa vedere cosa intendo. (Inoltre, uno spazio aggiuntivo è sufficiente per aumentare il livello di rientro.)
res

@res Grazie, Python non è una lingua che uso molto come probabilmente puoi dire. Bel golf. (63 caratteri secondo il codice utente di Codegolf - deve contare le nuove righe).
Gareth,

1
Puoi usare l'estensione di slicing per proteggere dall'essere x ''e salvare diversi caratteri scrivendox=x[c==x[0:1]:]
Nolen Royalty

4

GolfScript (22 caratteri)

X[0]+Y{1$(@={\}*;}/0=!

Suppone che l'input sia preso come due variabili predefinite Xe Y, sebbene ciò sia piuttosto insolito in GolfScript. Lascia 1per vero o 0per falso in pila.



4

Burlesque (6 caratteri)

6 caratteri in Burlesque: R@\/~[ (supponendo che x e y siano in pila. Vedi qui in azione.)



3

PHP, 90 caratteri

<?function s($x,$y){while($a<strlen($y))if($y[$a++]==$x[0])$x=substr($x,1);return $x=="";}

È possibile rimuovere la ifdichiarazione e semplificare a $x=substr($x,$y[$a++]==$x[0]): ideone.com/Ch9vK
mellamokb

Anche qui c'è una soluzione di 82 caratteri leggermente più corta che usa la ricorsione: ideone.com/IeBns
mellamokb

3

Scala 106:

def m(a:String,b:String):Boolean=(a.size==0)||((b.size!=0)&&((a(0)==b(0)&&m(a.tail,b.tail))||m(a,b.tail)))

3

CoffeeScript 112 100 95 89

Il mio primo tentativo di code golf ... spero di non vergognarmi della mia famiglia!

z=(x,y)->a=x.length;return 1if!a;b=y.indexOf x[0];return 0if!++b;z x[1..a],y[b..y.length]

Modifica : risulta che Coffeescript è più indulgente di quanto pensassi con gli spazi bianchi.

Grazie a res e Peter Taylor per alcuni consigli per renderlo un po 'più elegante


Ancora qualche caratteri possono essere eliminati come segue (questo non verrà visualizzato a destra in un commento, ma credo che si può capire cosa intendo): z=(x,y)-> a=x.length return 1if a==0 b=y.indexOf x[0] return 0if b<0 z x[1..a],y[b+1..y.length]. (In alcuni browser, ad esempio Chrome, è possibile visualizzare correttamente il codice dei commenti facendo clic con il pulsante destro del mouse, quindi Ispeziona elemento.)
Ris

a.lengthnon sarà mai negativo, quindi puoi salvare un altro personaggio sostituendolo if a==0con if a<1. Non so come funzioni la tokenizzazione di CoffeeScript, ma se si scioglie if0come due token potresti salvarne altri due invertendo entrambe le condizioni (es if1>a.).
Peter Taylor,

Punti buoni. if1>anon è valido, ma if!aè ed è un personaggio più corto! Mi sono anche reso conto che avrei potuto radere un personaggio in più convertendolo b+1in be incrementandolo nella riga precedente, rendendo anche possibile lo stesso iftrucco dato che stava affrontando una situazione 0 / non-0.
Johno,

3

C #, 70 113 107 90 caratteri

static bool S(string x,string y){return y.Any(c=>x==""||(x=x.Remove(0,c==x[0]?1:0))=="");}

6
Questa ricerca non è una sottostringa piuttosto che una sottosequenza?
Gareth,

si, ho letto male. Ora dovrebbe essere risolto.
mizer

1
Per quanto divertente sia Linq, penso che tu possa risparmiare il 10% usando invece la ricorsione.
Peter Taylor,

Ecco il mio miglior tentativo. Ancora più a lungo. static bool S(string x,string y){if(x!=""&&y=="")return false;return x==""||S(y[0]==x[0]?x.Remove(0,1):x,y.Remove(0,1));}
mizer,

Puoi ridurre quello ricorsivo a x==""||y!=""&&S(...), ma è ancora più lungo della versione Linq aggiornata. Bel uso di Any!
Peter Taylor,

3

Mathematica 19 17 27

LongestCommonSequencerestituisce la sottosequenza non contigua più lunga di due stringhe. (Da non confondere LongestCommonSubsequence, che restituisce la sottosequenza contigua più lunga.

Di seguito viene verificato se la sottosequenza contigua più lunga è la prima delle due stringhe. (Quindi devi inserire la stringa più corta seguita dalla stringa più grande.)

LongestCommonSequence@##==#& 

Esempi

LongestCommonSequence@## == # &["", "z00"]
LongestCommonSequence@## == # &["z00", "z00"]
LongestCommonSequence@## == # &["anna", "banana"]
LongestCommonSequence@## == # &["Anna", "banana"]

True True True False

Il test critico è il terzo, perché "anna" è contenuta in modo non contiguo in "banana".


3

Python 3.8 (pre-release) , 42 byte

lambda a,b:''in[a:=a[a[:1]==c:]for c in b]

Provalo online!

Python 3.8 (pre-release) , 48 byte

lambda a,b,j=0:all((j:=1+b.find(c,j))for c in a)

Provalo online!

Python 2 , 48 byte

lambda a,b:re.search('.*'.join(a),b)>0
import re

Provalo online!

Copiato da questa risposta di Lynn . La >0può essere omesso se solo truthy / Falsey uscita è OK.

Python 2 , 50 byte

f=lambda a,b:b and f(a[a[:1]==b[0]:],b[1:])or''==a

Provalo online!

Python 2 , 50 byte

lambda a,b:reduce(lambda s,c:s[c==s[:1]:],b,a)==''

Provalo online!


Ottimo uso del tricheco.
Jonathan Allan,

2

C - 74 71 64

Questo non batte la soluzione di Peter Taylor, ma penso che sia abbastanza divertente (in più, questo è un programma di lavoro completo, non solo una funzione)

main(int c,char**v){for(;*v[1]!=0;++v[1])v[2]+=*v[1]==*v[2];return*v[2];}

main(int c,char**v){for(;*v[1];++v[1])v[2]+=*v[1]==*v[2];return*v[2];}


main(c,v)char**v;{while(*v[1])v[2]+=*v[1]++==*v[2];return*v[2];}

E non golfato:

main(int argc, char** argv){
   char * input = argv[1];
   char * test  = argv[2];

   // advance through the input string. Each time the current input
   // character is equal to the current test character, increment
   // the position in the test string.

   for(; *input!='\0'; ++input) test += *input == *test;

   // return the character that we got to in the test string.
   // if it is '\0' then we got to the end of the test string which
   // means that it is a subsequence, and the 0 (EXIT_SUCCESS) value is returned
   // otherwise something non-zero is returned, indicating failure.
   return *test;
}

Per provarlo puoi fare qualcosa come:

./is_subsequence banana anna && echo "yes" || echo "nope"    
# yes
./is_subsequence banana foobar && echo "yes" || echo "nope"    
# nope

!=0in una condizione è un po 'prolisso ... La funzione Program vs è qualcosa che la domanda deve specificare chiaramente, e qui no, quindi le risposte prendono diverse opzioni.
Peter Taylor,

Accidenti, questa !='\0'è una cattiva (buona?) Abitudine nello scrivere un codice non golfistico, l'ho lasciato scivolare nei miei ultimi due giri di golf, dovrò stare più attento in futuro. Per quanto riguarda il programma vs. la funzione, sì, hai assolutamente ragione.
Gordon Bailey,

@GordonBailey mi dispiace per l'urto, ma ho apportato alcune modifiche in una versione più breve.
oldrinb,

2

Pitone, 66 62 59 58 caratteri

Una specie di soluzione divertente, sicuramente un bel problema.

def f(n,h,r=0):
 for c in h:r+=n[r:r+1]==c
 return r==len(n)

2

Ruby 32 30 28

f=->a,b{b.match a.tr'','.*'}

Questo restituirà MatchDataistanza se aè sottosequenza bo nilmeno.

Vecchia versione che trova sottostringa anziché sottosequenza

Ruby 15

f=->a,b{!!b[a]}

Utilizzando il String#[](str)metodo che restituisce strif strè una sottostringa di selfe !!per restituire Booleanse il valore restituito può essere utilizzabile come booleano (e non deve essere trueo false), può essere solo 13 caratteri:

f=->a,b{b[a]}

Restituirà nilse anon è una sottostringa di b.


2
Bello, ma la domanda richiede una sottosequenza piuttosto che una sottostringa.
Gareth,

2

SWI-Prolog, SICStus

L' elenco secondario predicato incorporato / 2 di SICStus verifica se tutti gli elementi del primo elenco compaiono anche nel secondo elenco. Questo predicato è disponibile anche in SWI-Prolog tramite la libreria di compatibilità, che può essere caricata dalla query [library(dialect/sicstus/lists)]..

Esecuzione di esempio:

25 ?- sublist("","z00").
true.

26 ?- sublist("z00","z00").
true .

27 ?- sublist("z00","00z0").
false.

28 ?- sublist("aa","anna").
true .

29 ?- sublist("anna","banana").
true .

30 ?- sublist("Anna","banana").
false.

Il conteggio dei byte può tecnicamente essere 0, dal momento che tutto ciò che stiamo facendo qui è una query, proprio come il modo in cui eseguiamo un programma e forniamo input ad esso.


2

PHP, 41 byte

stampa 1 per vero e niente per falso

<?=!levenshtein($argv[1],$argv[2],0,1,1);

Se vengono eseguiti solo inserimenti dalla parola 1 alla parola 2, il conteggio è zero per i casi reali

levenshtein

Provalo online!

PHP, 57 byte

stampa 1 per vero e 0 per falso

Crea un Regex

<?=preg_match(_.chunk_split($argv[1],1,".*")._,$argv[2]);

Provalo online!


1
-2 byte: l'inizializzazione .*non è necessaria. -2 byte: non assegnare $argva $a. +24 byte: necessità array_map(preg_quote())di caratteri speciali (utilizzare le parentesi come delimitatori per evitare il secondo preg_quoteparametro.)
Tito

2
@Titus il primo. * È necessario per l'input di una stringa vuota e per l'input devo solo gestire una stringa alfanumerica maiuscola / minuscola eventualmente vuota. Hai ragione con la citazione se ci sono caratteri speciali. Grazie per aver conteggiato l'assegnazione. Copia e incolla con una soluzione precedente e non pensarci
Jörg Hülsermann

1
preg_matchnon si lamenterà di una regex vuota fintanto che i delimitatori sono lì. Abbinerà qualsiasi cosa. Ma la funzione preg_quote è a soli 22 byte, non 24: array_map(preg_quote,str_split(...)).
Tito

1
Ma poi, l'input è garantito per essere alfanumerico :) Ma non hai ancora bisogno del comando .*.
Tito

2

Brachylog , 2 byte

⊆ᵈ

Provalo online!

Come per questa risposta, è un predicato incorporato che dichiara una relazione tra le variabili di input e output ed è un meta-predicato che lo modifica per dichiarare invece la stessa relazione tra il primo e il secondo elemento della variabile di input (e unificare la variabile di output con il secondo elemento, ma poiché si tratta di un problema decisionale che qui non ha importanza). X⊆Yè un'affermazione che X è una sottosequenza di Y, quindi lo è anche[X,Y]⊆ᵈ .

Questo predicato (che ovviamente genera in caso di esito positivo o negativo che stampa true.o false.quando viene eseguito come programma) accetta l'input come un elenco di due stringhe. Se l'input è un po 'più flessibile ...

Brachylog , 1 byte

Provalo online!

Accetta la stringa X come variabile di input e la stringa Y come variabile di output. Output in esito positivo o negativo, come in precedenza. Se eseguito come programma completo, X viene fornito come input e Y come primo argomento della riga di comando.


1

CoffeeScript 73

Ecco una risposta alternativa a CoffeeScript, usando regex invece della ricorsione:

z=(x,y)->a='.*';a+=c+'.*'for c in x;b=eval('/'+a+'/');(y.replace b,'')<y

Se il pagliaio corrisponde a un regex molto avido costruito dall'ago, verrà sostituito con una stringa vuota. Se il pagliaio è più corto di quello iniziato, l'ago era una sottosequenza.

Restituisce false quando xey sono entrambe stringhe vuote. Pensa che abbiamo bisogno di un filosofo che ci dica se una stringa vuota è una sottosequenza di se stessa!

(Inserito come una risposta separata dalla mia precedente perché sembra abbastanza diverso da giustificarlo).


1

PowerShell, 38

$args[1]-clike($args[0]-replace'','*')

Naturalmente, qualsiasi soluzione basata sulla corrispondenza di regex o pattern presenta gravi problemi di prestazioni con stringhe più lunghe. Ma poiché la mancanza è il criterio ...


1

Una sorta di anti-soluzione che genera tutte le sottosequenze di Y:

Python 93

l=len(y)
print x in[''.join(c for i,c in zip(bin(n)[2:].rjust(l,'0'),y)if i=='1')for n in range(2**l)]

1

APL (31)

La gestione delle stringhe è un po 'carente in APL.

{(⊂'')∊N←⍵↓⍨¨1,⍨=/⊃¨⍵:~×⍴⊃N⋄∇N}

utilizzo:

      {(⊂ '') ∊N ← ⍵ ↓ ⍨¨1, ⍨ = / ⊃¨⍵: ~ × ⍴⊃N⋄∇N} 'anna' 'banana'
1
      {(⊂ '') ∊N ← ⍵ ↓ ⍨¨1, ⍨ = / ⊃¨⍵: ~ × ⍴⊃N⋄∇N} 'Anna' 'banana'
0
      {(⊂ '') ∊N ← ⍵ ↓ ⍨¨1, ⍨ = / ⊃¨⍵: ~ × ⍴⊃N⋄∇N} '' 'banana'
1

1

Python 132

Simile a Daniero. Non è la soluzione più semplice, ma è stato divertente provare. Sono nuovo di Python, quindi sono sicuro che potrei accorciarlo se sapessi qualcosa di più.

def f(i):
    s=x;j=0
    while j<len(s):t=~i%2;s=[s[:j]+s[j+1:],s][t];j+=t;i>>=1
    return s==y
print True in map(f,range(1,2**len(x)))

1

Python - 72

def f(a,b):
 c=len(a)
 for i in b:a=a.replace(i,"",1)
 print len(a+b)==c

1

Python ( 75 52)

s=lambda a,b:a==''or b>''and s(a[a[0]==b[0]:],b[1:])

Semplice soluzione ricorsiva. Giocare a golf per la prima volta, quindi sono molto apprezzati tutti i suggerimenti su come ridurre questo valore :)

Testato con il seguente:

assert s('anna', 'banana') == True
assert s('oo0', 'oFopp0') == True
assert s 'this', 'this is a string') == True
assert s('that', 'this hat is large') == True
assert s('cba', 'abcdefg') == False

Grazie a @lirtosiast per alcuni trucchi booleani intelligenti.


1
Puoi s=lambda a,b:a==''or b>''and s(a[a[0]==b[0]:],b[1:])
ridurlo

Grazie, è intelligente, usare il booleano come indice 0/1 nella giuntura :)
foslock

1

PHP, 75 65 64 byte

for(;$p=@strpos(_.$argv[2],$c=$argv[1][$i++],$p+1););echo""==$c;

accetta input dagli argomenti della riga di comando; stampa 1per vero, stringa vuota per falso. Corri con -r.

spiegazione:

  • strposritorna falsese l'ago $cnon si trova nel pagliaio $argv[2](dopo la posizione $p),
    causando la rottura del cappio.
  • strposritorna anche falseper un ago vuoto, interrompendo il ciclo alla fine di $argv[1].
  • Se $argv[1]è una sottosequenza di $argv[2], $csarà vuota quando il ciclo si interrompe.
  • strposdeve @sopprimere l' Empty needleavvertimento.

+$pinvece di $p+1ciò non è necessario il carattere di sottolineatura
Jörg Hülsermann

@ JörgHülsermann +1è necessario per avanzare nella stringa del pagliaio; e il trattino basso evita l' $p=-1inizializzazione. Ma ... posso evitare false!==.
Tito

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.