10
\$\begingroup\$

This is a fairly simple code golf challenge. Your program, given an ASCII string, is to parse that string into two strings, which it will evaluate. If the second string is "later" than the first one, it will return a 1, if it is "earlier" than the first one, it will return a -1, and if they are the same, it will return 0. To clarify what "later" and "earlier" mean, let's take a look at ASCII character codes. You need to compare each character of the string, treating each of them as digits of a number. Later refers to a larger number, occurring after a smaller number. Strings will be formatted with a hyphen character to separate the two input groups.

Take a look at this example:

7-9 as an input should return 1.

7 converts to ASCII code 55, and 9 converts to ASCII code 57.

As 57 occurs numerically after 55, 9 is later than 7.

Another example:

LKzb-LKaj as an input should return -1

The ASCII code sequences for this are 76-75-122-98 and 76-75-97-106

This is a code golf challenge, and byte count is how entries will be scored.

Any input from the 95 printable ASCII characters is accepted, excluding spaces, and hyphens for anything but separating the input. In addition, strings are not guaranteed to be the same length.

Good luck!

EDIT: To be more clear, each character is to be treated like a digit in a number. In the example LKzb-LKaj, though j is later than b, z is later than a, and since it is a more significant digit, it takes precedence. A string supplied will always be at minimum 3 characters, eliminating empty strings from the scope of this problem.

EDIT: Here are some more test cases, for your help:

  • A-9 -> -1
  • 11-Z -> -1
  • 3h~J*-3h~J* -> 0
  • Xv-Y0 -> 1
\$\endgroup\$
14
  • 1
    \$\begingroup\$ Are the two strings guaranteed to be the same length? \$\endgroup\$
    – es1024
    Commented Jul 30, 2015 at 19:01
  • 5
    \$\begingroup\$ Test case 11-Z->-1 makes no sense given the current wording of the question. Z (90) is greater than 1 (49) and is the most significant letter. Please clarify how strings of different lengths are compared. \$\endgroup\$ Commented Jul 30, 2015 at 22:40
  • 2
    \$\begingroup\$ And what about A-AA? \$\endgroup\$
    – user42682
    Commented Jul 31, 2015 at 4:32
  • 2
    \$\begingroup\$ @SamWeaver I know leftmost is the most significant digit hence my confusion as to why 11>Z in your examples when 1<Z. There must be some undefined behaviour to do with strings of differing lengths or the example is wrong. \$\endgroup\$ Commented Jul 31, 2015 at 8:23
  • 3
    \$\begingroup\$ As previously explained: each string is to be treated as a digit in a base-127 number. If you were to count in this system, you would begin with a character, increment it up to the barrier of printable characters, ~ at 126, then would increment the next digit by one, returning the initial digit to !. Each increase in the most significant digit is equivalent to increment the second-most-significant digit by 127. \$\endgroup\$
    – Sam Weaver
    Commented Jul 31, 2015 at 13:15

15 Answers 15

10
\$\begingroup\$

Pyth - 11 bytes

Easy, uses ._ sign to get the sign and C to get char codes.

._-F_CMcz\-

Try it online here.

Test suite.

._               Sign of number
 -F              Fold subtraction (this finds difference of a tuple)
  _              Reverse list to get correct order of operands when subtracting
   CM            Map char, already treats strings as digits of base256 number
    c \-         Split by "-"
     z           Input
\$\endgroup\$
1
  • \$\begingroup\$ Very nice! Performs as expected. \$\endgroup\$
    – Sam Weaver
    Commented Jul 30, 2015 at 20:43
7
\$\begingroup\$

CJam, 12 bytes

l'-/esfb~\-g

Try it online in the CJam interpreter.

How it works

l   e# Read a line from STDIN.
'-/ e# Split it at spaces.
es  e# Push the current time (milliseconds since epoch).
fb  e# Consider each string as digits in base huge-number.
~\  e# Dump the results and reverse their order.
-g  e# Subtract and apply sign function.
\$\endgroup\$
1
  • \$\begingroup\$ Excellent! This passes all test cases. \$\endgroup\$
    – Sam Weaver
    Commented Jul 30, 2015 at 21:00
6
\$\begingroup\$

Java, 86 118

int f(String...s){return(int)Math.signum((s=s[0].split("-"))[1].compareTo(s[0])*(s[0].length()==s[1].length()?1:-1));}  

A very strange way of comparing strings. Made a quick fix so it passes additional test cases, will look for more golfiness later.

Thanks to Vartan in comments for signum suggestion

\$\endgroup\$
7
  • \$\begingroup\$ Doesn't java's compare return 1,0,-1 anyways? I know it's not guaranteed to, but is there any case of it not? in which case return s[0].compareTo(s[1]); \$\endgroup\$
    – Vartan
    Commented Jul 30, 2015 at 20:38
  • \$\begingroup\$ This is nice, but it does not pass the test case of 11-Z returning -1, it returns 1. \$\endgroup\$
    – Sam Weaver
    Commented Jul 30, 2015 at 20:58
  • \$\begingroup\$ Ah, this wasn't clear to me before those test cases were added. Fixed. \$\endgroup\$
    – Geobits
    Commented Jul 30, 2015 at 21:25
  • \$\begingroup\$ @Vartan No, it returns the difference in value at the first non-matching position (or the difference in length if there is one and all characters match). For example, "A".compareTo("Z") returns -25. Unfortunately. \$\endgroup\$
    – Geobits
    Commented Jul 30, 2015 at 21:47
  • \$\begingroup\$ Can you explain this line? i = a!=b ? b-a : s[1].compareTo(s[0]); I don't seem to get it... Also, you could maybe use Math.signum and save yourself declaring i; \$\endgroup\$
    – Vartan
    Commented Jul 30, 2015 at 21:58
4
\$\begingroup\$

Perl, 31 bytes

#!/usr/bin/perl -p
/-/;$_=($`.$'^$`)cmp($'.$`^$')

30 bytes + 1 byte for -p. Accepts input on STDIN.

Explanation

When the operands to cmp have different lengths, like chicken and egg, they are aligned like this:

c  h  i  c  k  e  n
e  g  g  \0 \0 \0 \0

so that egg > chicken (\0 is a null byte). But we want them to be aligned like this:

c  h  i  c  k  e  n
\0 \0 \0 \0 e  g  g

so that chicken > egg.

To do this, we concatenate them, once with chicken before egg and once with egg before chicken:

c  h  i  c  k  e  n  e  g  g
e  g  g  c  h  i  c  k  e  n

Now that our two strings are the same length, we remove the leading word using an XOR to get:

\0 \0 \0 \0 \0 \0 \0 e  g  g
\0 \0 \0 c  h  i  c  k  e  n

And now we can use cmp to find which came first. (There, I said it!)

\$\endgroup\$
1
  • \$\begingroup\$ Very clever- Bravo! \$\endgroup\$
    – Sam Weaver
    Commented Aug 2, 2015 at 17:47
3
\$\begingroup\$

Python 2, 88 characters

a=raw_input().split('-');print-cmp(*(map(ord,s.rjust(max(map(len,a)),'\0'))for s in a))

cmp doesn't do the right thing when you have two different length strings, so I have to pad both of them with the null character (which ord converts to 0) to handle that case. Unfortunately, that added about 35 characters, plus it's now two lines instead of one because I need both the length of the input and to iterate over it.

\$\endgroup\$
7
  • \$\begingroup\$ Unfortunately, this is not a valid solution. The following test case: 1-2, which should return 1 returns -1. Clever work though. \$\endgroup\$
    – Sam Weaver
    Commented Jul 31, 2015 at 0:48
  • \$\begingroup\$ Whoops, it appears the operands are swapped. That's super weird, I tested it with a couple of your test cases and I thought it worked fine! No matter, I can change it without changing the character count. Give it a shot now. \$\endgroup\$ Commented Jul 31, 2015 at 15:07
  • \$\begingroup\$ Your edit did fix that case, but it now fails the 11-A case, which should return -1, instead of returning 1 in this example. \$\endgroup\$
    – Sam Weaver
    Commented Jul 31, 2015 at 15:11
  • \$\begingroup\$ I don't like your rules for length. I fixed it at the cost of about 35 characters, and I don't think I could make it better. \$\endgroup\$ Commented Jul 31, 2015 at 17:53
  • 1
    \$\begingroup\$ I managed to get a shorter answer than yours by encoding the string into hex format then parsing that string as an int. In python 2, it seems to default to big-endianness for this. Thus, the 0 padding is no longer required. \$\endgroup\$
    – Dunes
    Commented Jul 31, 2015 at 19:30
2
\$\begingroup\$

R, 54 Bytes

This requires the pracma library. It splits the input string on the -. Right justifies the strings. Ranks them and does a diff.

So for 11-7 we end up with the strings "11" and " 7". The rank of these is [2, 1]. The difference is -1. For 3h~J*-3h~J* we get "3h~J*" and "3h~J*". The rank of these is [1.5, 1.5] with a diff of 0.

diff(rank(pracma::strjust(scan(,'',sep='-'),"right")))

Test Examples

> diff(rank(pracma::strjust(scan(,'',sep='-'),"right")))
1: LKzb-LKaj
3: 
Read 2 items
[1] -1
> diff(rank(pracma::strjust(scan(,'',sep='-'),"right")))
1: A-9
3: 
Read 2 items
[1] -1
> diff(rank(pracma::strjust(scan(,'',sep='-'),"right")))
1: 11-Z
3: 
Read 2 items
[1] -1
> diff(rank(pracma::strjust(scan(,'',sep='-'),"right")))
1: 3h~J*-3h~J*
3: 
Read 2 items
[1] 0
> diff(rank(pracma::strjust(scan(,'',sep='-'),"right")))
1: Xv-Y0
3: 
Read 2 items
[1] 1
\$\endgroup\$
1
  • \$\begingroup\$ Clever. Nice work :) \$\endgroup\$
    – Alex A.
    Commented Jul 31, 2015 at 16:06
2
\$\begingroup\$

CoffeeScript, 143 140 139

f=(s)->[a,b]=((t=s.split '-').map (y)->Array((m=Math.max) 1, 1+(m ((l=(c)->c.length) t[0]),l t[1])-l y).join('\u0000')+y);`b<a?-1:(b>a?1:0)`

Here is a jsfiddle with the results (look in the console)

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

PERL, 46 36 Bytes

print$2cmp$1if"@ARGV"=~/(\S+)-(\S+)/

Converts the argv list into a string, splits by the hyphen into a left and right sided no spaces arg, then returns a cmp call.

\$\endgroup\$
3
  • \$\begingroup\$ I suspect you can get rid of a number of spaces and the ; \$\endgroup\$
    – MickyT
    Commented Jul 30, 2015 at 22:30
  • \$\begingroup\$ Should be able to get away with: "@ARGV"=~/-/;print$`cmp$' (untested) \$\endgroup\$
    – Jarmex
    Commented Jul 31, 2015 at 6:43
  • 1
    \$\begingroup\$ Good idea to use cmp, but it doesn't work when the string lengths are different. "A" cmp "9" is 1 while "11" cmp "Z" is -1, even though both inputs should return the same value for this challenge. \$\endgroup\$ Commented Jul 31, 2015 at 15:05
1
\$\begingroup\$

Python 3, 84 bytes

x,y=[int.from_bytes(i.encode(),"big")for i in input().split("-")];print((x<y)-(y<x))

Split the string input by "-". Convert the unicode strings to bytes strings, then interpret these byte strings as big-endian integers. Finally do the comparison -- (un)fortunately cmp is no longer available in Python 3.

Python 2, 69 bytes

print -cmp(*[int(i.encode("hex"),16)for i in raw_input().split("-")]) 
\$\endgroup\$
1
  • \$\begingroup\$ You can shave off a character by removing the space between print and cmp. \$\endgroup\$ Commented Jul 31, 2015 at 19:54
1
\$\begingroup\$

Python 2, 79 bytes

Pretty simple solution, and it's easy to understand. Compares string lengths, then compares the strings lexigraphically.

Try it here

s,t=raw_input().split('-')
x,y=len(s),len(t)
print(x<y)*2-1if x-y else cmp(t,s)
\$\endgroup\$
1
\$\begingroup\$

perl5, 64

perl -aF- -pe '@f=map{length}@F;$_=$f[1]<=>$f[0]||$F[1]cmp$F[0]'

Just run it from the commandline. although it would look better with a new line but that costs 1 char.

perl -laF- -pe '@f=map{length}@F;$_=$f[1]<=>$f[0]||$F[1]cmp$F[0]'

This longer version handles mismatched lengths correctly.

\$\endgroup\$
4
  • \$\begingroup\$ /-/,$_=$`cmp$' would be easier, and you can skip the -aF- bit. Also, I count this a 20 (16 for $_=$F[1]cmp$F[0], and 4 for paF-, saved to a file and run as perl -paF- file.pl). \$\endgroup\$
    – primo
    Commented Jul 31, 2015 at 15:36
  • 1
    \$\begingroup\$ As I noted on Eric's answer, cmp doesn't work when the two strings are of different lengths, like with 11-Z. \$\endgroup\$ Commented Jul 31, 2015 at 16:04
  • \$\begingroup\$ @ThisSuitIsBlackNot, fixed. \$\endgroup\$
    – hildred
    Commented Aug 2, 2015 at 6:54
  • \$\begingroup\$ Nice. You can golf that down to 39 with /-/;$_=length$'<=>length$`||$' cmp$` and -p. ($` stores everything before the regex match, $' stores everything after.) Using map actually costs more bytes than just calling length twice. \$\endgroup\$ Commented Aug 2, 2015 at 13:17
0
\$\begingroup\$

F#, 53

fun s->let[|a;b|]=s="";s.Split[|'-'|]in b.CompareTo a

This is in the form an anonymous function (lambda), so you have to paste it and provide the parameter directly after is (or, using the piping notation). For example (in FSI):

> "7-9" |> fun s->let[|a;b|]=s="";s.Split[|'-'|]in b.CompareTo a
1
> "abc-abc" |> fun s->let[|a;b|]=s="";s.Split[|'-'|]in b.CompareTo a
0
> "LKzb-LKaj" |> fun s->let[|a;b|]=s="";s.Split[|'-'|]in b.CompareTo a
-1
\$\endgroup\$
0
\$\begingroup\$

JavaScript ES6, 46 43 bytes

f=s=>((a=s.split('-'))[1]>a[0])-(a[1]<a[0])
\$\endgroup\$
4
  • \$\begingroup\$ Good work, but this does not accomplish test case 2: 11-Z should return -1 but it returns 1. \$\endgroup\$
    – Sam Weaver
    Commented Jul 30, 2015 at 21:03
  • 1
    \$\begingroup\$ @SamWeaver Indeed, that was added after the answer and breaks other answers also. Can you explain why '11'>'Z' when '11'<'ZZ' there is nothing in the question about how to compare string of different lengths or what value an empty string has. \$\endgroup\$ Commented Jul 30, 2015 at 21:14
  • \$\begingroup\$ The intent of the question never changed, I only added those test cases and clarification because I realized I was not clear enough in the beginning. You are right that I never defined the value of an empty string, and I will update the question accordingly. Those test cases did not change the behavior or goal of the question, merely clarified it. The examples you named function as such because each character must be treated as an individual "digit" in a number who's base is equivalent to all printable ASCII characters. This mechanic of the question never changed, simply became more clear. \$\endgroup\$
    – Sam Weaver
    Commented Jul 30, 2015 at 21:42
  • 1
    \$\begingroup\$ @SamWeaver Changing from undefined behaviour to defined does change it. Nothing is not a character. Unless its the null character, which this handles. \$\endgroup\$ Commented Jul 30, 2015 at 21:45
0
\$\begingroup\$

Ruby, 59 bytes

a,b=gets.chomp.split ?-
p (b.size<=>a.size).nonzero?||b<=>a
\$\endgroup\$
0
\$\begingroup\$

05AB1E, 12 11 9 bytes

'-¡₄ö¥0.S

Try it online or verify all test cases.

Explanation:

'-¡          # Split the (implicit) input on '-'
             #  i.e. 'LKzb-LKaj' → ['LKzb','LKaj']
   ₄ö        # Convert both parts to a Base-1000 number
             #  i.e. ['LKzb','LKaj'] → [21020061037,21020036045]
     ¥       # Push the deltas (subtraction between each sub sequential pair) of the list
             #  i.e. [21020061037,21020036045] → [-24992]
      0.S    # Get the sign [1 for a>0; -1 for a<0; 0 for a==0] (and output implicitly)
             #  i.e. [-24992] → [-1]
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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