12
\$\begingroup\$

Given a string of unsorted alphanumeric characters, e.g.

ABC321STPpJqZZr0

output a ", "-separated list of character ranges, sorted by ASCII value, ignoring case and removing duplicates (i.e. outputting only uppercase and numeric characters), e.g.

0-3, A-C, J, P-T, Z

Rules

  • The length of your program is your base score, as usual.
  • You must initialize (hardcode) the above example within your program, but you may discount the length of that example from your program length, e.g. for char* s="ABC321STPpJqZZr0"; you may discount 16 chars, the other 11 chars counting toward your program length.

Bonus (+50 bounty)

  • As this was a real problem encountered by my coworker today, needing to be written in Tcl 8.0.5 (an ancient version, lacking many of the latest Tcl built-ins), I'll award 50 points to whomever writes the shortest Tcl 8.0.5 solution, if there are at least 2 valid submissions in Tcl 8.0.5.
\$\endgroup\$
  • \$\begingroup\$ @FezVrasta - I intentionally wrote ", " to include the space, but we can leave your edit and let this comment serve as that indication. \$\endgroup\$ – Andrew Cheong Feb 11 '14 at 0:19
  • \$\begingroup\$ Why intentionally include GolfScript? Why not allow other languages, such as Befunge? \$\endgroup\$ – Justin Feb 11 '14 at 1:14
  • \$\begingroup\$ We can say all is fair game. I just won't be able to check most of them very easily. \$\endgroup\$ – Andrew Cheong Feb 11 '14 at 1:15
  • \$\begingroup\$ So is that a Code-Golf tag then? \$\endgroup\$ – VisioN Feb 11 '14 at 8:35
  • 1
    \$\begingroup\$ @Chron - Good catch. A-B in my case but since there have already been many submissions, let's allow both ways. \$\endgroup\$ – Andrew Cheong Feb 11 '14 at 9:21

10 Answers 10

5
\$\begingroup\$

Ruby, 87-16=71

EDIT: Had to add some characters so that two-character ranges are displayed correctly. Also using ?[ instead of ?Z to fix a bug with ranges ending in Z.

$><<[*?0..?[].join.gsub(/[^ABC321STPpJqZZr0]/i,$/).gsub(/\B.+\B/,?-).scan(/.-.|./)*', '

You can see the Ideone run here.

\$\endgroup\$
  • \$\begingroup\$ +1 For one-liner. Very clever use of various methods; This is really brilliant. \$\endgroup\$ – daniero Feb 11 '14 at 4:12
  • 1
    \$\begingroup\$ Note that gsub(/[]/i) is shorter than tr(''.upcase) by 2 characters. Moreover, scan(/.+/) -> split saves 5, and $><< instead of puts another one. \$\endgroup\$ – Howard Feb 11 '14 at 7:36
  • \$\begingroup\$ @Howard Great suggestions, thanks! \$\endgroup\$ – Paul Prestidge Feb 11 '14 at 9:15
2
\$\begingroup\$

Julia, 131

julia> l=sort(unique(uppercase("ABC321STPpJqZZr0")))
julia> prod([!(c+1 in l)?"$c"*(c==l[end]?"":", "):!(c-1 in l)?"$c":(c+1 in l)&&!(c+2 in l)?"-":"" for c in l])

"0-3, A-C, J, P-T, Z"

Not supported by Ideone.com, and will probably be crushed anyway.

\$\endgroup\$
  • 1
    \$\begingroup\$ Thanks anyway! The Ideone.com constraint was only so I could test it but I suppose I can trust the integrity of golfers and remove that rule. +1, anyway. \$\endgroup\$ – Andrew Cheong Feb 10 '14 at 23:10
2
\$\begingroup\$

C#, 221 bytes

class P{
    static void Main(){
        var s="ABC321STPpJqZZr0";
        var l=new int[257];
        foreach(int c in s.ToUpper())
            l[c]=1;
        var r="";
        for(int i=0;i<255;){
            if(l[i++]-l[i]<0)
                r+=", "+(char)i;
            else if(l[i+1]-l[i]<0)
                r+="-"+(char)i;
        }
        System.Console.Write(r.Substring(2));
    }
}
\$\endgroup\$
2
\$\begingroup\$

C, 193

char*s="ABC321STPpJqZZr0";
int c[99];memset(c,0,396);while(*s){++c[toupper(*s++)];}for(int i=0,f=1,r=0;
i<=99;++i){if(!r&&c[i])r=i;if(r&&!c[i]){if(!f)printf(", ");putchar(r);
if(i-r>1)printf("-%c",i-1);r=f=0;}}
\$\endgroup\$
  • \$\begingroup\$ Can you add a small explanation? \$\endgroup\$ – Justin Feb 11 '14 at 6:42
  • \$\begingroup\$ Iterate over the string, accumulating a count of instances of each alphanumeric character. Then, iterate over all alphanumeric characters in alphabetical order, writing out the start of each compact range and, if appropriate, a dash followed by the end of the range. If this is not the first range that's been written, add the comma-space separator. Code must be embedded in a main() function with appropriate headers (stdio, string, ctypes) included, so I kinda cheated there. \$\endgroup\$ – warrenm Feb 11 '14 at 7:25
2
\$\begingroup\$

GolfScript 57 54 52

 'ABC321STPpJqZZr0'
 {.95>32*-}%.|:x..{(}%&-x..{)}%&-+$2/{.|'-'*}%', '*

Try it here.

The code first capitalizes everything:

{.95>32*-}%

Then gets unique characters and saves it in a variable:

.|:x

Then, we get the characters whose direct predecessors are not in the string (so that they are the beginning part of a range):

..{)}%&-x

We similarly get the ends of ranges with x..{)}%&-.

Now actually form the ranges by concatenating the lists, sorting, and splitting into groups of 2:

+$2/

The rest is just formatting, using * as string join.

\$\endgroup\$
  • 1
    \$\begingroup\$ In the output, the ranges need to be separated by ', ' and not just ',' \$\endgroup\$ – Paul Prestidge Feb 11 '14 at 1:30
  • 1
    \$\begingroup\$ Also .95>{32-}{}if -> .95>32*- saves 5 characters. \$\endgroup\$ – Howard Feb 11 '14 at 5:29
  • \$\begingroup\$ @Howard Great! I knew that part was suboptimal. \$\endgroup\$ – Ben Reich Feb 11 '14 at 5:47
  • 1
    \$\begingroup\$ @Chron Fixed the space issue! \$\endgroup\$ – Ben Reich Feb 11 '14 at 5:47
2
\$\begingroup\$

Q, 94

{","sv(,/){{"-"sv(?) -1 1#\:x}'[cut[;a]0,1_(&)1<(-':)"i"$'a:asc upper[x]inter y]}[x]'[.Q`n`A]}
\$\endgroup\$
1
\$\begingroup\$

Python 2.x, 304 - 16 = 288

This can surely be golfed further, all comments welcome!

e=[""]*11;f=[""]*27
for c in"ABC321STPpJqZZr0".lower():e["0123456789".find(c)]=f["abcdefghijklmnopqrstuvwxyz".find(c)]=c
e[-1]=f[-1]=""
def h(j):
 g=[];k=l=i=0
 for e in j:
  if e:
   if not l:k=i;l=1
  elif l:l=g.append((k,i-1))
  i+=1
 print", ".join([j[m],j[m]+"-"+j[n]][n-m>1]for m,n in g)
h(e);h(f)
\$\endgroup\$
1
\$\begingroup\$

Rebol (218 - 16 = 202)

m: s: sort uppercase unique"ABC321STPpJqZZr0"i: :to-integer f: does[either 1 = length? x: copy/part m s[x][rejoin[x/1"-"last x]]]while[not tail? s: next s][if(1 + i pick back s 1)!=(i s/1)[prin join f", "m: s]]print f

Non-minified version:

m: s: sort uppercase unique "ABC321STPpJqZZr0"
i: :to-integer

f: does [
    either 1 = length? x: copy/part m s [x] [rejoin [x/1 "-" last x]]
]

while [not tail? s: next s][
    if (1 + i pick back s 1) != (i s/1) [
        prin join f ", "
        m: s
    ]
]

print f
\$\endgroup\$
1
\$\begingroup\$

q [116 chars]

{.a:();{m:6h$x;.a:.a,$[m[1]=1+m[0];45;m[0],44,m 1];1_x}/[x:asc distinct upper x];p where differ 6h$p:-3_10h$x[0],.a}

Usage

{.a:();{m:6h$x;.a:.a,$[m[1]=1+m[0];45;m[0],44,m 1];1_x}/[x:asc distinct upper x];p where differ 6h$p:-3_10h$x[0],.a}"ABC321STPpJqZZr0"
Output
"0-3,A-C,J,P-T,Z"

There is a scope of saving chars, i'll try some other method and post it.

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

Tcl 8.0.5, 344 (360 bytes)

set a ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
set s string
set x [join [lsort [split [$s toupper ABC321STPpJqZZr0] ""]] ""]
regsub -all (.)\\1+ $x \\1 x
set i 36
while {[incr i -1]} {set j -1
while {$i+[incr j]<36} {set y [$s range $a $j [expr $i+$j]]
regsub $y $x [$s index $y 0]-[$s index $y end],\  x}}
while {[regsub -all {(\w)(\w)} $x {\1, \2} x]} {}
puts $x

Tcl 8.0.5, 340 (356 bytes)

Tinkering with the rename command yielded some fun tricks! I've documented them in another thread.

rename rename &
& set =
& regsub R
& string S
& while W
= a ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
= x [lsort [split [S toupper ABC321STPpJqZZr0] ""]]
R -all {(.) \1+| } $x \\1 x
= i 36
W {[incr i -1]} {= j -1
W {$i+[incr j]<36} {= y [S range $a $j [expr $i+$j]]
R $y $x [S index $y 0]-[S index $y end],\  x}}
W {[R -all {(\w)(\w)} $x {\1, \2} x]} {}
puts $x

Tcl 8.0.5, 332 (348 bytes) [Unstable—depends on $PATH]

info script ""
set tcl_interactive 1
set a ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
set x [lso [sp [st toupper ABC321STPpJqZZr0] ""]]
regs -all {(.) \1+| } $x \\1 x
set i 36
wh {[inc i -1]} {set j -1
wh {$i+[inc j]<36} {set y [st range $a $j [exp $i+$j]]
regs $y $x [st index $y 0]-[st index $y end],\  x}}
wh {[regs {(\w)(\w)} $x {\1, \2} x]} {}
pu $x

Credit to @JohannesKuhn for the interactive trick.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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