Take the 2-minute tour ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Given strings X and Y, determine whether X is a subsequence of Y. The empty string is regarded as a subsequence of every string. (E.g., '' and 'anna' are subsequences of 'banana'.)

Input

  • X, a possibly-empty case-sensitive alphanumeric string
  • Y, a possibly-empty case-sensitive alphanumeric string

Output

  • True or False (or equivalents), correctly indicating whether X is a subsequence of Y.

I/O examples

X      Y        output

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

Criteria

  • The shortest program wins, as determined by the number of bytes of source code.

Example programs

share|improve this question
    
Why is 'anna' substr of 'banana'? –  kaoD Apr 26 '12 at 5:04
1  
@kaoD - anna is a subsequence (but not a substring) of banana. String X is a subsequence of string Y just if X can be obtained from Y by deleting zero or more of the elements of Y; e.g., deleting the b and the second a from banana gives anna. –  r.e.s. Apr 26 '12 at 13:33
1  
This has about a single solution in every scripting language offering regex that's both trivial to see and impossible to golf further. –  Joey Apr 27 '12 at 14:50

31 Answers 31

up vote 14 down vote accepted

Perl, 18 chars

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

Input is given in the variables $x and $y, result is the value of the expression (in scalar context). Note that $x is modified in the process. (Yes, I know using $_ instead of $x would let me save four chars, but that feels a bit too cheesy for me.)

How does it work?

The first part, $x=~s//.*/g, inserts the string .* between each character in $x. The second part, $y=~$x, treats $x as a regexp and matches $y against it. In Perl regexps, .* matches zero or more arbitrary characters, while all alphanumeric characters conveniently match themselves.

share|improve this answer

Ruby, 32 characters

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

This solution returns nil if x isn't a subsequence of y and a number otherwise (i.e. ruby equivalents to false and true). Examples:

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)
share|improve this answer
1  
i did basically the same thing, but it's too similar so i won't post it. i think it is acceptable to leave off the lambda, which would leave you with y=~/#{[*x.chars]*".*"}/ (23 chars). cheers! –  padde Apr 26 '12 at 12:46
1  
or even y=~/#{x.split("")*".*"}/ (21 chars) :) –  padde Apr 26 '12 at 12:53
    
@padde The split one is actually 24 chars. –  Howard Apr 27 '12 at 0:23
    
sorry, i guess i accidentally left off the y=~ while fiddling with this in irb... –  padde Apr 27 '12 at 13:27
    
My version is 2 char shorter. –  Łukasz Niemier Sep 12 '12 at 9:47

Python (48 chars)

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

Same approach as Howard's Ruby answer. Too bad about Python's need to import the regex package and its "verbose" lambda. :-)

share|improve this answer

Haskell, 51 37

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

Thanks to Hammar for the substantial improvement. It's now an infix function, but there seems to be no reason why it shouldn't.

Demonstration:

GHCi> :{
GHCi| zipWith (%) [""   , "z00", "z00" , "anna"  , "Anna"]
GHCi|             ["z00", "z00", "00z0", "banana", "banana"]
GHCi| :}
[True,True,False,True,False]
share|improve this answer
    
Since the empty list is smaller than any other list, you can simplify the base cases to s x y=x<=y. Also, you can save a few more by making it an operator and using an @-pattern instead of (f:l). This cuts it down to 37 characters: h@(f:l)%(g:m)=f==g&&l%m||h%m;x%y=x<=y –  hammar Apr 18 '12 at 6:38

Python, 59 characters

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

I figured my answer would be better expressed in Python.

Edit: Added r.e.s.'s suggestions.

share|improve this answer
    
Surely given x="a" and y="ab" you would exit the loop with y=="b" and return false? –  Peter Taylor Apr 15 '12 at 22:29
    
@PeterTaylor Yeah, I noticed when I was running the examples as tests after posting that I've mixed x and y up. In my functions y needs to be a subsequence of x. I think I'd better change them to avoid any confusion. –  Gareth Apr 15 '12 at 22:31
    
You can get this down to 59 chars: def s(x,y): for c in y: if x:x=x[c==x[0]:] return x=="". It doesn't display correctly in a comment, but I think you can see what I mean. (Also, one added space is enough to increase the indent level.) –  r.e.s. Apr 15 '12 at 23:20
    
@r.e.s. Thanks, Python's not a language I use much as you can probably tell. Nice golfing. (63 characters according to the Codegolf userscript - it must be counting the newlines). –  Gareth Apr 15 '12 at 23:26
    
The if statement can all go on one line, with no space after the colon, bringing the count down to 59. –  r.e.s. Apr 15 '12 at 23:32

GolfScript (22 chars)

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

Assumes that input is taken as two predefined variables X and Y, although that is rather unusual in GolfScript. Leaves 1 for true or 0 for false on the stack.

share|improve this answer

C (52 chars)

s(char*x,char*y){return!*x||*y&&s(*x-*y?x:x+1,y+1);}

Test cases

share|improve this answer

Burlesque (6 chars)

6 chars in Burlesque: R@\/~[ (assuming x and y are on the stack. See here in action.)

share|improve this answer

PHP, 90 characters

<?function s($x,$y){while($a<strlen($y))if($y[$a++]==$x[0])$x=substr($x,1);return $x=="";}
share|improve this answer
    
You can remove the if statement and simplify to $x=substr($x,$y[$a++]==$x[0]): ideone.com/Ch9vK –  mellamokb Apr 16 '12 at 22:08
    
Also here is a slightly shorter 82-character solution using recursion: ideone.com/IeBns –  mellamokb Apr 16 '12 at 22:19

C #, 70 113 107 90 characters

static bool S(string x,string y){return y.Any(c=>x==""||(x=x.Remove(0,c==x[0]?1:0))=="");}
share|improve this answer
6  
Doesn't this search for a substring rather than a subsequence? –  Gareth Apr 15 '12 at 23:17
    
yes, I misread. Should be fixed now. –  mizer Apr 18 '12 at 1:41
1  
As fun as Linq is, I think you can save 10% by using recursion instead. –  Peter Taylor Apr 18 '12 at 8:13
    
Here's my best attempt. Still longer. 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 Apr 26 '12 at 2:15
    
You can reduce the recursive one to x==""||y!=""&&S(...), but it's still longer than the updated Linq version. Nice use of Any! –  Peter Taylor Apr 26 '12 at 8:05

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)))
share|improve this answer

CoffeeScript 112 100 95 89

My first attempt at code golf... hope I don't shame my family!

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]

Edit: turns out Coffeescript is more forgiving than I thought with whitespace.

Thanks to r.e.s. and Peter Taylor for some tips for making it a bit sleeker

share|improve this answer
    
A few more chars can be eliminated as follows (this won't display right in a comment, but I think you can see what I mean): 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 some browsers, e.g. Chrome, you can see comment code properly displayed by right-clicking, then Inspect Element.) –  r.e.s. Apr 23 '12 at 17:33
    
a.length is never going to be negative, so you can save one character more by replacing if a==0 with if a<1. I don't know how CoffeeScript's tokenisation works, but if it lexes if0 as two tokens you could save two more by reversing both conditions (i.e. if1>a). –  Peter Taylor Apr 23 '12 at 21:42
    
Good points. if1>a isn't valid, but if!a is and is a character shorter! I also realised that I could shave an extra character converting b+1 to b and incrementing it on the previous line, also making the same if trick possible since it was dealing with a 0/non-0 situation. –  Johno Apr 24 '12 at 9:59

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
share|improve this answer
    
!=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 Apr 24 '12 at 13:32
    
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 Apr 24 '12 at 17:55
    
@GordonBailey sorry for the bump, but I made a few changes into a shorter version. –  oldrinb Sep 9 '12 at 14:54

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)
share|improve this answer

Mathematica 19 17 27

LongestCommonSequence returns the longest non-contiguous subsequence of two strings. (Not to be confused with LongestCommonSubsequence, which returns the longest contiguous subsequence.

The following checks whether the longest contiguous subsequence is the first of the two strings. (So you must enter the shorter string followed by the larger string.)

LongestCommonSequence@##==#& 

Examples

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

True True True False

The critical test is the third one, because "anna" is contained non contiguously in "banana".

share|improve this answer

C, 23:

while(*y)*x-*y++?0:x++;

result in *x

http://ideone.com/BpITZ

share|improve this answer

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).

share|improve this answer

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)]
share|improve this answer

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.

share|improve this answer
2  
Nice, but the question asks for a subsequence rather than a substring. –  Gareth Apr 19 '12 at 7:12

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
share|improve this answer

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)))
share|improve this answer

Javascript, 104 chars

function _(x,y){f=true;for(c in x){if(y.indexOf(x[c])>-1)y=y.replace(x[c],"");else{f=!f;break}}return f}

Ungolfed

function _(x,y){
f=true;
    for(c in x)
    {
        if(y.indexOf(x[c])>-1)
           y=y.replace(x[c],"");
        else {
            f=!f;
            break;
        }
    }
    return f;
}
share|improve this answer
    
This appears to test whether x is a substring of y, but it's supposed to test whether x is a subsequence of y. E.g., 'anna' is a subsequence of 'banana', but 'banana'.indexOf('anna')>-1 evaluates to false. –  r.e.s. Sep 19 '12 at 4:14
    
@r.e.s. : My bad dint read the question properly. Thanks –  Clyde Lobo Sep 19 '12 at 8:57
    
@r.e.s. posted a altogether new answer –  Clyde Lobo Sep 19 '12 at 9:17
    
What does the new answer do for _("ab", "ba")? –  Peter Taylor Sep 19 '12 at 13:19
    
returns true. demo jsfiddle.net/yvAdT –  Clyde Lobo Sep 19 '12 at 18:28

Python - 72

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

C, 120

main(i,c){char x[99],y[99];c=0;gets(y),gets(x);for(i=0;y[i]!='\0';)c+=y[i++]==x[c]?1:0;puts(x[c]=='\0'?"True":"False");}
share|improve this answer
    
You can save at least 15 chars by moving c=0 to the loop initialiser and eliminating every instance of == in favour of "non-zero is truthy" conditions. –  Peter Taylor Apr 16 '12 at 16:36

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 ...

share|improve this answer

J (20 chars)

(<x)e.(#:i.2^#y)<@#y

The input is given in the variables x and y. It makes a list of all subsequences of y, so don't use it for very big strings.

share|improve this answer

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.

share|improve this answer

Python (72)

import itertools as I;any(tuple(X)==Z for Z in I.permutations(Y,len(X)))
share|improve this answer
    
No, that use of permutations ignores the required order of the elements; e.g., X='z00' and Y='00z0' should output False (whereas your program outputs True). –  r.e.s. Mar 17 at 22:42

BASIC: : 18 chars

print instr(a$, b$)

Heh heh heh. Good old QBasic.

share|improve this answer

bash & grep: 39

grep "$(sed 's/./&.*/g'<<<"$X")"<<<"$Y"

The return value of grep is the answer.

share|improve this answer
    
Apart from the things which can go horribly wrong with meta-characters, this tests for substring rather than subsequence. –  Peter Taylor Mar 11 at 23:38
    
Well special characters are a special case (this is golf, not serious programming). But I have to fix the substring/subsequence issue, I simply didn't read the instructions properly. –  orion Mar 12 at 9:19

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.