文字列Xは文字列Yのサブシーケンスですか?


23

ストリングX及びYが与えられると、Xがあるかどうかを決定サブ空の文字列がすべての列のサブシーケンスとみなされるYの。(たとえば、''およびの'anna'サブシーケンスです'banana'。)

入力

  • X、空の可能性がある大文字と小文字を区別する英数字文字列
  • Y、空の可能性がある大文字と小文字を区別する英数字文字列

出力

  • TrueまたはFalse(または同等のもの)。XがYのサブシーケンスであるかどうかを正しく示します。

I / Oの例

X      Y        output

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

基準

  • ソースコードのバイト数で決まる最短のプログラムが優先されます。

サンプルプログラム


1
なぜ「anna」は「banana」の下位区分なのですか?
kaoD

4
@kaoDは- annaであるサブシーケンス(しかしないのストリング)banana。文字列Xは、Yのゼロ個以上の要素を削除してYからXを取得できる場合にのみ、文字列Yのサブシーケンスです。たとえば、からを削除し、bからの2番目を指定abananaますanna
解像度

2
これには、すべてのスクリプト言語で1つのソリューションがあり、正規表現を提供します。
ジョーイ

回答:


18

Perl 5、17バイト(+1?)、フルプログラム

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

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

pように、perlインタープリターにフラグを付けて呼び出しperl -pe 's//.*/g;$_=<>=~$_'ます。パーこの挑戦が最初に掲載された際に設立されたスコアリングルールは、このフラグは1つの余分バイトがかかります。より最近の規則、AFAICTの下では、無料の場合があります。

いずれにしても、入力文字列は、stdinの改行で区切られた個別の行で指定する必要があります。(stdoutへの)出力1は、最初の入力文字列が2番目の入力文字列の場合であり、そうでない場合は何もありません。

両方の入力行の最後に改行が必要であることに注意してください。そうしないと、プログラムが正しく動作しません。または、lコマンドラインフラグを呼び出しに追加して、perlで改行を削除することもできます。有効なスコアリングルールに応じて、1バイト余分にかかる場合とそうでない場合があります。このフラグを使用すると、出力に改行も追加されることに注意してください。

元のバージョン(スニペット、18バイト/文字)

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

入力は変数$x$yで与えられ、結果は式の値です(スカラーコンテキストで)。$xはプロセスで変更されることに注意してください。(はい、$_代わりに使用すると$x4文字を節約できますが、スニペットでそれを行うと少し安っぽく感じます。)

どのように機能しますか?

最初の部分、は$x=~s//.*/g、の.*各文字の間に文字列を挿入します$x。2番目の部分は$y=~$x$x正規表現として扱われ、$yそれと一致します。Perl正規表現では、.*0個以上の任意の文字に一致しますが、すべての英数字は自分自身に便利に一致します。


アウト(新規?)コンセンサスによると、提出物はスニペットではなくプログラムまたは機能でなければなりません。提出がそれを満たさない場合は、編集を検討してください。
user202729

@ user202729:このチャレンジはそのコンセンサスよりもかなり古いので、遡及的に適用することが想定されない限り、このスレッドの答えはおそらく「祖父」になっているはずです。コマンドラインスイッチのカウント方法に応じて、1バイト/文字よりも短くなる場合があります(バイトベースのカウントもこの課題よりも新しいことに注意してください)。
イルマリカロネン

9

ルビー、32文字

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

この溶液に戻るnil場合xのサブないy、そうでなければ数(すなわち、ルビー当量falsetrue)。例:

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
基本的に同じことをしましたが、あまりにも似ているので投稿しません。ラムダを省いても問題ないと思いますy=~/#{[*x.chars]*".*"}/(23文字)。乾杯!
パトリックオスシティ

1
またはy=~/#{x.split("")*".*"}/(21文字):)
パトリックオスシティ

@padde分割されたものは実際には24文字です。
ハワード

1
申し訳ありませんが、私が誤ってオフに左推測y=~... IRBにこのいじるながら
パトリックOscity

私のバージョンは2文字短くなっています。
Hauleth

7

ハスケル、 51 37

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

大幅な改善をしてくれたHammarに感謝します。現在は中置関数ですが、そうすべきでない理由はないようです。

デモンストレーション:

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

空のリストは他のリストよりも小さいため、ベースケースをに単純化できますs x y=x<=y。また、演算子にして、の@代わりに-pattern を使用することで、さらにいくつかを保存できます(f:l)。これにより、37文字にh@(f:l)%(g:m)=f==g&&l%m||h%m;x%y=x<=y
短縮されます。– hammar

6

Python(48文字)

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

ハワードのRubyの答えと同じアプローチ。Pythonが正規表現パッケージとその「詳細」をインポートする必要があるのは残念lambdaです。:-)


1
ラムダは冗長です。
電卓

4

Python、59文字

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

私の答えはPythonで表現した方が良いと思いました。

編集:resの提案を追加しました。


確かに与えられx="a"y="ab"あなたはループを終了しy=="b"、戻りfalseますか?
ピーターテイラー

@PeterTaylorええ、私はミックスxしてyアップしたことを投稿した後、テストとしてサンプルを実行しているときに気付きました。私の機能yではのサブシーケンスである必要がありますx。混乱を避けるためにそれらを変更した方が良いと思います。
ガレス

これは59文字まで取得できますdef s(x,y): for c in y: if x:x=x[c==x[0]:] return x==""。コメントに正しく表示されませんが、私が言っていることはわかると思います。(また、インデントレベルを上げるには1つのスペースを追加するだけで十分です。)
解像度

@resありがとう、Pythonはあなたがたぶん言うことができるほど多く使う言語ではない。素敵なゴルフ。(Codegolfユーザースクリプトによると63文字-改行を数えている必要があります)。
ガレス

1
あなたはされてXから保護するために拡張スライスを使用することができます''書き込むことによって、いくつかの文字保存x=x[c==x[0:1]:]
ノレンロイヤリティを

4

GolfScript(22文字)

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

入力は2つの定義済み変数Xおよびとして受け取られると仮定しますがY、GolfScriptではかなり珍しいです。葉1真または0スタックに偽のために。



4

バーレスク(6文字)

バーレスク6つの文字は: R@\/~[ (Xを仮定し、yはスタック上にある参照してください。ここでアクションで)。



3

PHP、90文字

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

ifステートメントを削除して、次のように簡略化でき$x=substr($x,$y[$a++]==$x[0])ます。ideone.com
mellamokb

また、再帰を使用した少し短い82文字のソリューションもあります。ideone.com
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

コードゴルフの私の最初の試み...私は私の家族を恥じないことを願っています!

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]

編集:Coffeescriptは、空白で考えていたよりも寛容であることがわかりました。

少し洗練されたものにするためのヒントをくれたresとPeter Taylorに感謝します


さらにいくつかの文字を次のように削除することができます(これはコメントでは正しく表示されませんが、私が言っていることはわかると思います)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]。(Chromeなどの一部のブラウザーでは、右クリックして[エレメントを検査]を選択すると、コメントコードが正しく表示されます。)
解像度

a.lengthあなたは置き換えることによって、より多くの1つの文字を保存することができますので、マイナスになるだろうことはありませんif a==0if a<1。CoffeeScriptのトークン化がどのように機能するかはわかりませんがif0、2つのトークンとして字句解析する場合は、両方の条件を逆にすることでさらに2つを節約できます(つまりif1>a)。
ピーターテイラー

良い点。if1>aは有効ではありませんif!aが、より短い文字です!また、前の行に変換b+1bて増分する余分な文字を削ることができif、0/0以外の状況を扱っていたため、同じトリックが可能になることにも気付きました。
ジョノ

3

C#、 70 113 107 90文字

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

6
これはサブシーケンスではなくサブストリングを検索しませんか?
ガレス

はい、誤解し​​ています。今すぐ修正する必要があります。
マイザー

1
Linqと同じくらい楽しいですが、代わりに再帰を使用すると10%節約できると思います。
ピーターテイラー

これが私の最善の試みです。さらに長い。 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));}
マイザー

再帰的なものをに減らすことができますがx==""||y!=""&&S(...)、更新されたLinqバージョンよりも長くなります。の素敵な使用Any
ピーターテイラー

3

Mathematica 19 17 27

LongestCommonSequence2つの文字列の最長の非連続サブシーケンスを返します。(LongestCommonSubsequence最長の連続したサブシーケンスを返すと混同しないでください。

以下は、最も長い連続したサブシーケンスが2つの文字列の最初のものであるかどうかをチェックします。(したがって、短い文字列に続いて大きな文字列を入力する必要があります。)

LongestCommonSequence@##==#& 

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

True True True False

「anna」は「banana」に非連続的に含まれているため、重要なテストは3番目のテストです。


3

Python 3.8 (pre-release), 42 bytes

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

Try it online!

Python 3.8 (pre-release), 48 bytes

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

Try it online!

Python 2, 48 bytes

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

Try it online!

Copied from this answer of Lynn. The >0 can be omitted if just truthy/falsey output is OK.

Python 2, 50 bytes

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

Try it online!

Python 2, 50 bytes

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

Try it online!


Great use of the walrus.
Jonathan Allan

2

C - 74 71 64

This doesn't beat Peter Taylor's solution, but I think it's pretty fun (plus, this is a complete working program, not just a function)

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];}

And ungolfed:

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;
}

To test it you can do something like:

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

!=0 in a condition is a bit verbose... Program vs function is something which the question needs to specify clearly, and here it doesn't, so the answers take different options.
Peter Taylor

Damn, that !='\0' is a bad (good?) habit from writing non-golf code, I've let that slip into my last two rounds of golf, I'll have to be more careful in the future. As to program vs. function, yes, you're absolutely right.
Gordon Bailey

@GordonBailey sorry for the bump, but I made a few changes into a shorter version.
oldrinb

2

Python, 66 62 59 58 chars

Kind of a fun solution, definitely a neat problem.

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'','.*'}

This will return MatchData instance if a is subsequence of b or nil otherwise.

Old version that find substring instead of subsequence

Ruby 15

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

Using String#[](str) method that returns str if str is a substring of self and !! to return Boolean if returned value can be usable as boolean (and don't need to be true or false) then it can be only 13 chars:

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

It will return nil if a is not a substring of b.


2
Nice, but the question asks for a subsequence rather than a substring.
Gareth

2

SWI-Prolog, SICStus

The built-in predicate sublist/2 of SICStus checks whether all the items in the first list also appear in the second list. This predicate is also available in SWI-Prolog via compatibility library, which can be loaded by the query [library(dialect/sicstus/lists)]..

Sample run:

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.

The byte count can technically be 0, since all we are doing here is querying, much like how we run a program and supply input to it.


2

PHP, 41 Bytes

prints 1 for true and nothing for false

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

If only insertions from word 1 to word 2 done the count is zero for true cases

levenshtein

Try it online!

PHP, 57 Bytes

prints 1 for true and 0 for false

Creates a Regex

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

Try it online!


1
-2 bytes: leading .* is unnecessary. -2 bytes: don´t assign $argv to $a. +24 bytes: needs array_map(preg_quote()) for special characters (use parentheses as delimiters to avoid second preg_quote parameter.)
Titus

2
@Titus the leading .* is necessary for the input of an empty string and for the input I must only handle a possibly-empty case-sensitive alphanumeric string. You are right with the quote if there are special characters. Thank you for counting the assign. Copy and paste by an earlier solution and not think about it
Jörg Hülsermann

1
preg_match will not complain about an empty regex as long as the delimiters are there. It will just match anything. But preg_quote is only +22 bytes, not +24: array_map(preg_quote,str_split(...)).
Titus

1
But then, input is guaranteed to be alphanumeric :) But you still don´t need the leading .*.
Titus

2

Brachylog, 2 bytes

⊆ᵈ

Try it online!

As with this answer, is a built-in predicate that declares a relationship between the input and output variables, and is a meta-predicate that modifies it to declare that same relationship between the first and second elements of the input variable instead (and unify the output variable with the second element but as this is a decision problem that doesn't end up mattering here). X⊆Y is an assertion that X is a subsequence of Y, therefore so is [X,Y]⊆ᵈ.

This predicate (which of course outputs through success or failure which prints true. or false. when it's run as a program) takes input as a list of two strings. If input is a bit more flexible...

Brachylog, 1 byte

Try it online!

Takes string X as the input variable and string Y as the output variable. Outputs through success or failure, as before. If run as a full program, X is supplied as the input and Y is supplied as the first command line argument.


1

CoffeeScript 73

Here's an alternative CoffeeScript answer, using regexes instead of recursion:

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

If the haystack matches a very greedy regex constructed from the needle, it will be replaced with an empty string. If the haystack is shorter than it started, the needle was a subsequence.

Returns false when x and y are both empty strings. Think we need a philosopher to tell us if an empty string is a subsequence of itself!

(Posted as a separate answer from my previous because it feels different enough to justify it).


1

PowerShell, 38

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

Of course, any such regex- or pattern-matching-based solution has severe performance problems with longer strings. But since shortness is the criterion ...


1

A sort of anti-solution generating all subsequences of 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)

String handling is a bit lacking in APL.

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

usage:

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

1

Python 132

Similar to Daniero's. Not the easiest solution, but it was fun to try. I'm new to Python, so I'm sure I could make it shorter if I knew a little bit more.

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

Simple recursive solution. First time golfing, so any tips on whittling this down are much appreciated :)

Tested with the following:

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

Thanks to @lirtosiast for some clever boolean tricks.


1
You can get this down to 52 characters: s=lambda a,b:a==''or b>''and s(a[a[0]==b[0]:],b[1:])
lirtosiast

Thanks, that's clever, using the boolean as the 0/1 index into the splice :)
foslock

1

PHP, 75 65 64 bytes

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

takes input from command line arguments; prints 1 for true, empty string for false. Run with -r.

explanation:

  • strpos returns false if needle $c is not in the haystack $argv[2] (after position $p),
    causing the loop to break.
  • strpos also returns false for an empty needle, breaking the loop at the end of $argv[1].
  • If $argv[1] is a subsequence of $argv[2], $c will be empty when the loop breaks.
  • strpos needs @ to suppress Empty needle warning.

+$p instead of $p+1 after that ther is no need for the underscore
Jörg Hülsermann

@JörgHülsermann +1 is needed to advance in the haystack string; and the underscore avoids $p=-1 initialization. But ... I can avoid false!==.
Titus

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