2
\$\begingroup\$

this program has to take two strings and compare their length, then tell you which one is longer (string-a or string-b) and by how much

rules:

  • no using .length or other built-in length checking methods (duh!)
  • no using addition or subtraction, this includes improvised addition/subtraction, in case you find some sort of weird improvisation.
  • no > / < (greater then/less then) inside if / if-else statements (you can use them in loops though), this obviously includes >= etc. and no cheating (bool = a > b;if(bool))
  • emphasis is on short rather then efficient code
  • oh yeah almost forgot... good luck!
\$\endgroup\$
21
  • 1
    \$\begingroup\$ Is it code-golf? If so, tag it. If not, define the winning criteria. \$\endgroup\$
    – ugoren
    Sep 29, 2013 at 9:29
  • 2
    \$\begingroup\$ -1s are probably because your question is very unclear; you don't specify what format the strings are in, how to call the program, what the output should be, etc. \$\endgroup\$
    – Doorknob
    Sep 29, 2013 at 23:18
  • 5
    \$\begingroup\$ To Doorknob's comment I would add that questions of the form "Do a task that would normally be insanely trivial but with your hands cuffed behind your back" might make for amusing television, but in the context of programming challenges they largely come down to arguing that a particular language feature doesn't technically break the arbitrary restriction. \$\endgroup\$ Sep 30, 2013 at 9:13
  • 1
    \$\begingroup\$ "no > / < (greater then/less then) inside if / if-else" while(a>b){ do_something(); break;} is equivalent to an if... \$\endgroup\$
    – MrZander
    Sep 30, 2013 at 17:32
  • 3
    \$\begingroup\$ @PeterTaylor: To be fair, doing things with your hands cuffed behind your back is the reason I mostly golf in sed :P \$\endgroup\$
    – Hasturkun
    Oct 1, 2013 at 10:05

21 Answers 21

12
\$\begingroup\$

SED, 45 (43 + 2 for the -n flag)

s/./a/g
h
n
s/./b/g
G
:a
s/b\(.*\)a/\1/
ta

Expects input as two separate lines, outputs the difference in unary, using "a" or "b" to indicate the longer string. run with sed -n.

\$\endgroup\$
5
\$\begingroup\$

Perl, 87 78 - tells which is longer and by how much

alternative:

  • 72 - tells which is longer and by how much, no special message if equal

Perl script expecting 2 strings as command line arguments. Tells which one is longer and by how much. This one I tried to make it readable and not short.

#!/usr/bin/perl
use warnings;
use strict;

my ($x,$y)=@ARGV;
$x=$x=~s/.//g;
$y=$y=~s/.//g;
my @z=($x..$y);
my @w=($y..$x);
if (@z) {
    if ($#z) { print "2nd longer than 1st by $#z" }
    else { print "Equal length" }
}
else {
    print "1st longer than 2nd by $#w"
}

Same code as a one liner, counting 78 characters (output now prints "a3" if a > b by 3 characters, "0" if equal):

perl -E'($x,$y)=@ARGV;$_=s/.//g for$x,$y;@z=$x..$y;@w=$y..$x;say@z?$#z?"b$#z":0:"a$#w"'

Finally, since OP clarified that when they are equal it is not really important what it will print, we can save 6 more characters:

perl -E'($x,$y)=@ARGV;$_=s/.//g for$x,$y;@z=$x..$y;@w=$y..$x;say@z?"b$#z":"a$#w"'
\$\endgroup\$
1
  • 1
    \$\begingroup\$ You don't need to count the perl -e (or -E), or the single-quotes around the program, so yes, your score is currently 78. \$\endgroup\$
    – breadbox
    Sep 29, 2013 at 21:23
5
\$\begingroup\$

Tcl 8.6, 90

lmap c [split $a {}] d [split $b {}] {puts [expr {{}eq$d?{A}:{}eq$c?{B}:[continue]}];exit}

If you run Tcl 8.5, use foreach instead lmap.

This shows a nice feature of Tcl's foreach/lmap: It can walk over several lists at once.

\$\endgroup\$
4
\$\begingroup\$

J 17

Since there is no output specification: the length difference is outputted at the location of the shortest string

    longest =: *&.^/"1@(=&' ')@,:
    'foobar' longest 'abc'
0 3 NB. Means abc is shorter by 3 chars.
\$\endgroup\$
4
\$\begingroup\$

Javascript 96 92

x=prompt;i=c=0;for(p=x();c=p[i=-~i];);q=x();for(j=0;c=q[i=~-i,j=-~j];);alert(0<i&&p+i||q+-i)

Note 0<i&& contains no if statement but a logical operator, which is not forbidden.

Input asd,asdfg Output asdfg2

Means asdfg is 2 characters longer.

\$\endgroup\$
4
  • \$\begingroup\$ this is a fair loophole, and you program is cute. \$\endgroup\$ Sep 30, 2013 at 19:45
  • \$\begingroup\$ Could you explain how this works? c=p[i=-~i] would just be 1 wouldn't it? \$\endgroup\$
    – tristin
    Oct 1, 2013 at 21:10
  • \$\begingroup\$ @tristin I'm on mobile, but i'll try: ~ is the bitwise NOT operator and flips all bits. 0001 becomes 1110. So ~0 === -1 and - -1 === 1 -> ~1 === -2 and - -2 === 2 and so forth. I hope this was understandable :) \$\endgroup\$
    – C5H8NNaO4
    Oct 1, 2013 at 21:44
  • \$\begingroup\$ @tryingToGetProgrammingStraight Thanks :) \$\endgroup\$
    – C5H8NNaO4
    Oct 1, 2013 at 21:45
3
\$\begingroup\$

Bringing up the rear as always with the verbose language. :)

Java - 278

import java.util.*;class b{public static void main(String[]a){Stack z=new Stack(),y=new Stack();for(String q:a[0].split(""))z.push(q);for(String q:a[1].split(""))y.push(q);while(!z.empty()&&!y.empty()){z.pop();y.pop();}System.out.print(y.empty()?"1-"+z.size():"2-"+y.size());}}

With line breaks and tabs

import java.util.*;
class a{
    public static void main(String[]a){
        Stack z=new Stack(),y=new Stack();
        for(String q:a[0].split(""))z.push(q);
        for(String q:a[1].split(""))y.push(q);
        while(!z.empty()&&!y.empty()){
            z.pop();
            y.pop();
        }
        System.out.print(y.empty()?"1-"+z.size():"2-"+y.size());
    }
}
\$\endgroup\$
3
\$\begingroup\$

Ruby, 66 52 (shows only which one is longer)

f=->{gets.gsub(/./,?1)}
a=f[]
b=f[]
puts'sab'[a<=>b]

Prints s for same, a for string a, and b for string b.

Ruby, 184 173 146 143 139 140 (also shows how much longer it is)

f=->{gets.gsub(/./,?1)}
a=f[]
b=f[]
d=->e{Math.log10(e.to_i).floor.next.to_s}
puts(a==b ? ?s:(c=a.sub(b,''))!=a ? ?a+d[c]:?b+d[b.sub(a,'')])

Sample run:

c:\a\ruby>stringcmp
testing123
testing
a3

c:\a\ruby>stringcmp
codegolf.SE
code golf . stack exchange
b15

c:\a\ruby>stringcmp
test
test
s

c:\a\ruby>
\$\endgroup\$
5
  • \$\begingroup\$ second example contains +'s \$\endgroup\$
    – ljs.dev
    Oct 1, 2013 at 13:12
  • \$\begingroup\$ @lalalalalalalambda For string concatenation, not addition. \$\endgroup\$
    – Doorknob
    Oct 1, 2013 at 13:13
  • \$\begingroup\$ OK, I removed mine thinking concatenation would also count as addition, requiring strings to be joined via adding/removing elements to an array... just nit-picking though because mine is so darn long :P I don't think there is any hard n fast rule about it \$\endgroup\$
    – ljs.dev
    Oct 1, 2013 at 13:15
  • \$\begingroup\$ @Doorknob This + is not string concatenation: Math.log10(e.to_i)+1 (second version, third line). You can use integer's .next or .succ though. \$\endgroup\$
    – daniero
    Oct 10, 2013 at 12:47
  • \$\begingroup\$ @daniero Whoops, missed that. Fixed (only +1 char) \$\endgroup\$
    – Doorknob
    Oct 10, 2013 at 13:01
3
\$\begingroup\$

Mathematica 40

f = #~Count~0 & /@ PadLeft[Characters /@ {##}] &

Output is similar to the J version.

Example Usage:

f["looooong", "short"]

{0, 3}

f["short", "thisstringisveryverylong"]

{19, 0}

f["equal", "equal"]

{0, 0}

\$\endgroup\$
3
\$\begingroup\$

PHP (44)

-r'list(,$a,$b)=$argv;echo strcmp($a^$a,$b^$b);'
  • The -r argument and single quotes are not counted in the score.
  • string-a and string-b are accepted as command-line arguments.
  • The magnitude of the decimal number printed is the difference in length.
  • The sign indicates which string is longer. A positive number means string-a is longer. A negative number means string-b is longer. Zero means the strings are the same length.

PHP 5.4 (96)

Here, strcmp is avoided in favor of other string functions that are not so cheap.

-r'list(,$a,$b)=$argv;echo@strtr(explode(${"\3"^$c=trim(($a^=$a).b^($b^=$b).a)},$$c,2)[1],"\0",$c);'
  • Scoring and input format remain the same.
  • The difference in length is printed in unary.
  • The symbol a is used if string-a is longer; b is used if string-b is longer.
  • Nothing is printed if the strings are the same length (except in the commented version, which omits the error suppression operator @ and thus may report PHP notices and warnings).

Commented code:

<?php

list(, $a, $b) = $argv;

// Replace all bytes in both $a and $b with null bytes
// (Anything XORed with itself is zero.)
$a ^= $a;
$b ^= $b;

// PHP's bitwise XOR truncates its output to the shorter string's length,
// so only the marker ('a' or 'b') appended to the shorter string will
// remain after the null bytes in common are trimmed off. If $a is shorter,
// 'b' remains; likewise, if $b is shorter, 'a' remains.
$longer = trim($a . 'b' ^ $b . 'a'); // $c in the golfed code

// Flip bits 0 and 1 to switch 'a' to 'b' (or 'b' to 'a')
// ('a' === chr(0b1100001); 'b' === chr(0b1100010); "\3" === chr(0b11))
$shorter = "\3" ^ $longer;

// Remove the shorter string from the longer string
// $$shorter refers to $a if $shorter === 'a' or $b if $shorter === 'b'.
// $$longer works the same way.
$difference = explode($$shorter, $$longer, 2)[1];

echo strtr($difference, "\0", $longer);
\$\endgroup\$
2
\$\begingroup\$

JavaScript (prompt for input) - 128

I golfed it 2 more characters.

p=prompt,f=alert,i='lastIndexOf'
a=p().replace(/./g,'.')
b=p().replace(/./g,'.')
j=a[i](b),k=b[i](a)
~j&&f('a '+j)
~k&&f('b '+k)
\$\endgroup\$
3
  • \$\begingroup\$ "this program has to take two strings" \$\endgroup\$ Sep 29, 2013 at 17:49
  • \$\begingroup\$ You supply two strings a and b to a function F. Do you want command line style? \$\endgroup\$
    – tristin
    Sep 29, 2013 at 17:50
  • \$\begingroup\$ its not a stand-alone program, it doesnt matter how you get the strings, prompting or inputs or whatever is fine, it just has to be stand-alone. \$\endgroup\$ Sep 29, 2013 at 17:56
2
\$\begingroup\$

Python - 291 261 244 223 220 210 206

I got 206

import sys,itertools
q=sys.argv
h=[]
i=0
for k,g in itertools.groupby(map(lambda f,b:2 if f is None else 1 if b is None else 0,q[1],q[2])):h.append(list(g))
for i,a in enumerate(h[1],1):0
print q[h[1][0]],i

Sample Run

C:\pjs\codegolf>python last.py bananas apples
bananas 1
C:\pjs\codegolf>python last.py bananas hazlenuts
hazlenuts 2
\$\endgroup\$
5
  • 1
    \$\begingroup\$ Lots of room for golfing still. e.g. single-line blocks can go immediately after the colon on the previous line, like this: "if u:print [sys.argv[1],str(u)]". You can omit all of the indentation whitespace this way. \$\endgroup\$
    – breadbox
    Oct 1, 2013 at 17:46
  • \$\begingroup\$ thanks @breadbox, I pinched this for mine, too. was trying break if e to no avail, so if e:break saved me another 12 :) \$\endgroup\$
    – ljs.dev
    Oct 1, 2013 at 17:54
  • 1
    \$\begingroup\$ You can replace pass with 0 (or any other 1-character-Expression). Also, space after , and space before [ is unnecessary. (On the other hand, you don't even need the brackets in the print statements.) Oh, and the calls to list should be unnecessary (untested). I'll stop now :-) \$\endgroup\$ Oct 1, 2013 at 21:19
  • \$\begingroup\$ @WolframH I changed a little, but thank you about replace pass by 0 \$\endgroup\$ Oct 1, 2013 at 22:44
  • \$\begingroup\$ well done Doug and thanks to @WolframH, this CG thing is really educational! \$\endgroup\$
    – ljs.dev
    Oct 2, 2013 at 2:51
2
\$\begingroup\$

Bending the rules some...

JavaScript (92)

p=prompt
~function f(a,b) {
   a && !b && alert(0)
  !a &&  b && alert(1)

  f(a.slice(1), b.slice(1))
}(p(),p())

(Minified: p=prompt;~function f(a,b){a&&!b&&alert(0);!a&&b&&alert(1);f(a.slice(1),b.slice(1))}(p(),p()))

Takes two strings via prompts. Alerts the difference in unary (as with Hasturkun's solution), using 0s if the first string is longer and 1s if the second string is longer. Outputs each digit in a separate alert (ow), and terminates eventually when the call stack runs out (owww).

If we ignore the rule about no addition or subtraction, we could easily have the number be a nice (base 10) number whose sign denotes which string is longer:

p=prompt
alert(function f(a,b,n) {
  return a || b? f(a.slice(1), b.slice(1), n - !a + !b)
       :         n
}(p(),p(),0))

This version doesn't even wait for the call-stack to overflow!

\$\endgroup\$
2
\$\begingroup\$

Perl, 69 characters

sub l{l(map{substr$_,1}@_)if$_[0]&&$_[1];say pop()?2:1;die}l(<>,<>)

The gist is, recurse until one string is empty, then print the other. Run with perl -e CODE 2> /dev/null

\$\endgroup\$
2
\$\begingroup\$

Python 3: 125 91 90

Finally beat the JavaScript solutions :)

Prints both which is longer, and by how much.

Current (90 and Python 3):

I=input
q=a,b=I(),I()
while a+b:s=q[b!=""];a=a[1:];b=b[1:];i=a and b and-1or-~i
print(s,i)

Example output:

rees@Rees-Ubuntu:~/Python/CodeGolf$ python3 StringComparer.py
hi <- input one
hello <- input two
hello 3 <- output

Old (125 and Python 2):

r=raw_input
q=a,b=r(),r()
while a and b:a=a[1:];b=b[1:]
s=(q[0],q[1])[a==""]
i=0
while a or b:a=a[1:];b=b[1:];i=-~i
print s,i
\$\endgroup\$
1
\$\begingroup\$

Python, 708, 570, 566, 462, 492, 481, 480, 475, 363, 357, 354, 346, 343, 341, 340, 327, 315 (with whitespace)

My first CG, be gentle:

import sys
c=[1,2]
a=o=[]
l=d=e=v=0
s=sys.argv
r=range(0,99)
a=[zip(list(s[x]),r[1:]) for x in c]
a.insert(0,0)
for x in c:
    for p in a[x]:
        try:
            v=a[x==2 and 1 or 2][p[1]]
        except:
            l=s[x]
            o.append(1)
            e=1
    if e:break
o=zip(o,r)
print[l,o.pop()[1]]

Sample run:

me@home:~$ python diff.py bananas apples
['bananas', 1]
me@home:~$ python diff.py bananas hazlenuts
['hazlenuts', 2]
\$\endgroup\$
1
\$\begingroup\$

C, 230 200 193 characters

EDIT: Shortened it from 230 to 193 characters.

My first golf attempt. Maybe not a hole-in-one, but it works. Not being allowed to use strlen for this forces it to be fairly verbose in C. Maybe it can be shortened a bit?

a,b,w,i,l;
int main(int c,char **v){
    for(;a<256||b<256;i++){
        if(!v[1][i])a|=256;
        if(!v[2][i])b|=256;
        if(!(a&256))a++;
        if(!(b&256))b++;
    }
    a&=255;b&=255;
    w=a>b?0:1;
    l=w?b-a:a-b;
    printf("%s %i\n",v[w+1],l);
}

Or the uglier version:

a,b,w,i,l;int main(int c,char **v){for(;a<256||b<256;i++){if(!v[1][i])a|=256;if(!v[2][i])b|=256;if(!(a&256))a++;if(!(b&256))b++;}a&=255;b&=255;w=a>b?0:1;l=w?b-a:a-b;printf("%s %i\n",v[w+1],l);}

Example output:

N:\>golf.exe everything works
everything 5
\$\endgroup\$
3
  • \$\begingroup\$ it has to tell you how much it is longer by not how long the longer one is. \$\endgroup\$ Oct 17, 2013 at 9:37
  • \$\begingroup\$ Some tips: int in variable declarations is optional. No need for parentheses around a<256. if(!x)y -> x||y. i is initialized by default. \$\endgroup\$
    – ugoren
    Oct 17, 2013 at 19:29
  • \$\begingroup\$ Whoops, it outputs the difference now instead. Thanks for the tips ugoren. I knew "i" was initialized too, but I'm just so used to trying to write clear code! Like I said, my first golf. :) \$\endgroup\$
    – Mike C
    Oct 18, 2013 at 1:49
1
\$\begingroup\$

Powershell 140 (assumes a max difference of 999)

$c=@(compare($args[0]-split'.')($args[1]-split'.'))
$n=[collections.stack]@(999..1)
$c|%{$n.pop()}
if($c){$args[$c[0].sideindicator-eq'=>']}

Outputs nothing if the string lengths are equal. If the string lengths are not equal, the longer string is displayed; the last number is the difference.

\$\endgroup\$
1
\$\begingroup\$

C (gcc), 89 bytes

i;c;q;j;f(a,b)char*a,*b;{for(i=j=c=0;a[i]||b[j];a[i]&&++i,b[j]&&++j)a[i]&&b[j]?:++c;a=c;}

Try it online! I think this has room for improvement, but I'm not sure where. Abuses undefined behaviour, but it it Works On TIO™. Simply starts increment c when one of a[i] or b[j] is the null byte (the end of the string); i and j are incremented until they hit this null byte.

\$\endgroup\$
1
0
\$\begingroup\$

Clojure - 206

(defn is-longer [first second first-left second-left]
  (defn remaining [current count]
    (if (empty? current)
      (/ (Math/log count) (Math/log 2))
      (remaining (rest current) (bit-shift-left count 1))))
  (cond
   (empty? first-left) [2 (remaining second-left 1)]
   (empty? second-left) [1 (remaining first-left 1)]
   :else (is-longer first second (rest first-left) (rest second-left))))

Or minified:

(defn y [a b al bl] (defn x [u t] (if (empty? u) (/ (Math/log t) (Math/log 2)) (x (rest u) (bit-shift-left t 1)))) (cond (empty? al) [2 (x bl 1)] (empty? bl) [1 (x al 1)] :else (y a b (rest al) (rest bl))))

Or in prettierific:

Returns: [1|2 count]

Getting around not using + was a fun challenge.

\$\endgroup\$
0
\$\begingroup\$

Python, 194

import sys,itertools as T
A=sys.argv
B=[]
N,i=None,0
for k,g in T.groupby(map(lambda f,b:[[0,1][b is N],2][f is N],A[1],A[2])):B.append(list(g))
for i,j in enumerate(B[1],1):0
print A[B[1][0]],i
\$\endgroup\$
0
\$\begingroup\$

R - 120/114

Shows difference:

a=strsplit(scan(what='c'),"")
c=0
for(i in 1:2){for(y in a[[i]]){if(i-1)c=c+1 else c=c-1}}
d=abs(c)
cat(a[[(c==d)+1]],d)

Shows just the longer:

a=strsplit(scan(what='c'),"")
c=0
for(i in 1:2){for(y in a[[i]]){if(i-1)c=c+1 else c=c-1}}
cat(a[[(c==abs(c))+1]])
\$\endgroup\$

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